diff --git a/.gitattributes b/.gitattributes
index 28b9760b6bf139db2b8fcb9810034d6cedbdc9bd..0d37516c18a06f522621be1e26519e5b35934251 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -67,3 +67,89 @@ Assets/Projects/Ark.Portfolio/Admin_Projects.PNG filter=lfs diff=lfs merge=lfs -
Assets/Projects/Ark.Portfolio/Admin_ResumeManager.PNG filter=lfs diff=lfs merge=lfs -text
Assets/Projects/Ark.Portfolio/portfolio-hero.png filter=lfs diff=lfs merge=lfs -text
Assets/Site/Icon.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/data/ark_portfolio.sqlite filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Bryan.jfif filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Lenny[[:space:]]Avril.jpeg filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Mario.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_1.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_Hero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.React.Component/components-hero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAi_Hero.Png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAiHero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/Google_AI_Studio_2026-01-08T00_41_57.111Z.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot-hero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot1.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot10.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot11.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot12.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot13.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot14.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot2.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot3.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot4.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot5.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot6.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot7.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot8.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Capture.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/providers-hero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/trading-hero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png.jpg filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Dashobard.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Hero_Carrousel.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Projects.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_ResumeManager.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/portfolio-hero.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Site/Icon.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Backend/uploads/word/1d04f81e-fd89-4974-878e-449b90adfc5f.docx filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/App/Background.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/App/LogoArkAlliance.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/bot1.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot10.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot11.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot12.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot13.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot14.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot2.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot3.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot4.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot5.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot6.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot7.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Bot8.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.Share/assets/Capture.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/bot1.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot10.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot11.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot12.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot13.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot14.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot2.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot3.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot4.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot5.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot6.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot7.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Bot8.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/Ark.Alliance.Trading.Bot/Capture.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/Assets/icon/LogoArkAlliance.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/App/LogoArkAlliance.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/bot1.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot10.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot11.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot12.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot13.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot14.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot2.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot3.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot4.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot5.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot6.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot7.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Bot8.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Capture.PNG filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/assets/Icon.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/logo.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/public/LogoArkAlliance.png filter=lfs diff=lfs merge=lfs -text
+Ark.Alliance.StartupCms.Ai.UI/src/Assets/LogoArkAlliance.png filter=lfs diff=lfs merge=lfs -text
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/.env b/Ark.Alliance.StartupCms.Ai.Backend/.env
new file mode 100644
index 0000000000000000000000000000000000000000..25fc0a43829f1273afbeab8df6953c02469d8a63
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/.env
@@ -0,0 +1,8 @@
+PORT=3085
+DB_TYPE=sqlite
+# DB_HOST=localhost
+# DB_PORT=5432
+# DB_USER=postgres
+# DB_PASSWORD=postgres
+# DB_NAME=ark_portfolio
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/.env.example b/Ark.Alliance.StartupCms.Ai.Backend/.env.example
new file mode 100644
index 0000000000000000000000000000000000000000..049725a3c5b6312fee003374627ad7029b37fb98
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/.env.example
@@ -0,0 +1,49 @@
+# ═══════════════════════════════════════════════════════════════════════
+# Ark.Portfolio Backend - Environment Configuration
+# ═══════════════════════════════════════════════════════════════════════
+# Copy this file to .env and customize as needed
+
+# ─────────────────────────────────────────────────────────────────────────
+# Server Configuration
+# ─────────────────────────────────────────────────────────────────────────
+# Port for the backend server (default: 3085)
+PORT=3085
+
+# Node environment: development | production | test
+NODE_ENV=development
+
+# ─────────────────────────────────────────────────────────────────────────
+# Protocol Configuration
+# ─────────────────────────────────────────────────────────────────────────
+# Use HTTPS instead of HTTP (default: false)
+# When true, auto-generates self-signed certificate if none exists
+USE_HTTPS=false
+
+# ─────────────────────────────────────────────────────────────────────────
+# Database Configuration
+# ─────────────────────────────────────────────────────────────────────────
+DATABASE_TYPE=sqlite
+DATABASE_NAME=portfolio.db
+
+# ─────────────────────────────────────────────────────────────────────────
+# Authentication
+# ─────────────────────────────────────────────────────────────────────────
+# IMPORTANT: Change this in production!
+JWT_SECRET=change-this-secret-in-production
+JWT_EXPIRES_IN=24h
+
+# Admin password for initial user (defaults to Admin1234 if not set)
+# IMPORTANT: Set this via GitHub Secrets (ADMIN_KEY_CMS) in production!
+ADMIN_KEY_CMS=
+
+# ─────────────────────────────────────────────────────────────────────────
+# AI Services (Optional - encrypted in database)
+# ─────────────────────────────────────────────────────────────────────────
+# OPENAI_API_KEY=sk-...
+# ANTHROPIC_API_KEY=sk-ant-...
+# GOOGLE_AI_API_KEY=...
+
+# ─────────────────────────────────────────────────────────────────────────
+# CORS Configuration
+# ─────────────────────────────────────────────────────────────────────────
+CORS_ORIGIN=http://localhost:3080
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/.gitignore b/Ark.Alliance.StartupCms.Ai.Backend/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ba74aa156b367c1130d008dfe9b12bfaacfe0991
Binary files /dev/null and b/Ark.Alliance.StartupCms.Ai.Backend/.gitignore differ
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/Certificate/server.crt b/Ark.Alliance.StartupCms.Ai.Backend/Certificate/server.crt
new file mode 100644
index 0000000000000000000000000000000000000000..116300a99e3a6787a2be308b571578c9dadc7ba9
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/Certificate/server.crt
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDUDCCAjigAwIBAgIBATANBgkqhkiG9w0BAQsFADBFMRIwEAYDVQQDEwlsb2Nh
+bGhvc3QxIjAgBgNVBAoTGUFyay5Qb3J0Zm9saW8gRGV2ZWxvcG1lbnQxCzAJBgNV
+BAYTAkNBMB4XDTI1MTIzMTE4MzA0M1oXDTI2MTIzMTE4MzA0M1owRTESMBAGA1UE
+AxMJbG9jYWxob3N0MSIwIAYDVQQKExlBcmsuUG9ydGZvbGlvIERldmVsb3BtZW50
+MQswCQYDVQQGEwJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK0X
+nHahsBsDzxdBr9t7K4lGH0Giw42jgmaUsVQ9LdrD+pol5UoW2F4W6ERrEud9m4zT
+TfSMFsTs4Iw72CPuc1rK8TKyt1P+r2fAUj+d6OImkVwABpJJkaXhG7NjBias6pdM
+5xpHS2LsoFfVQEDL827R74PWUR3o8tvbS8frsa+w+FOXGYjnVGzSG/O/m5GYGKzX
+TzAB594S0T8oOlKaIu1aSKLXLKhjd2tYX3Yv+yenGSc0gN+9E4ybLlw4gpub4jjW
+R+j85Qzdw+6BzYHrVpbRXiunN611Ir9d8vKniuEYMs3SGaiamaWA0nbVsDbJei7t
+jZxoHl4VCMV9BpriSEsCAwEAAaNLMEkwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAw
+EwYDVR0lBAwwCgYIKwYBBQUHAwEwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAAB
+MA0GCSqGSIb3DQEBCwUAA4IBAQBYbck//uesmaRr1BebLGmYce4+TrGfAp49BA6h
+fbjhlrSqSpXBZi1JrqWWgPvux23NcMA5Pn0TAHTQViiOagSefdgZUFY73ytAB2PH
+AMoTyI34HhqCnSggvBDwJ3O5iX5Y1txcqNRq9frxUmBHNSFfYexKqNh71GMJA9/P
+Zv4c40wQK3Yt3+sM/8H9R9x+FPSYPTk+0ycJuEydc6HH/VEbb0OTPhzf6/+zHMW2
+3fDDCSxp0B64LBEwjnEsbGlKm/vOvrEizkXfcW5jpHgJVSo+7R8h3Sd1U3n5N74p
+zkshCRbIzr5PVEE+D20YNvwypKP/5VK4UxLdAof9FWezIgjN
+-----END CERTIFICATE-----
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/Certificate/server.key b/Ark.Alliance.StartupCms.Ai.Backend/Certificate/server.key
new file mode 100644
index 0000000000000000000000000000000000000000..5611ba5fd5839f27902113746fc972cbbde1ee21
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/Certificate/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEArRecdqGwGwPPF0Gv23sriUYfQaLDjaOCZpSxVD0t2sP6miXl
+ShbYXhboRGsS532bjNNN9IwWxOzgjDvYI+5zWsrxMrK3U/6vZ8BSP53o4iaRXAAG
+kkmRpeEbs2MGJqzql0znGkdLYuygV9VAQMvzbtHvg9ZRHejy29tLx+uxr7D4U5cZ
+iOdUbNIb87+bkZgYrNdPMAHn3hLRPyg6Upoi7VpIotcsqGN3a1hfdi/7J6cZJzSA
+370TjJsuXDiCm5viONZH6PzlDN3D7oHNgetWltFeK6c3rXUiv13y8qeK4RgyzdIZ
+qJqZpYDSdtWwNsl6Lu2NnGgeXhUIxX0GmuJISwIDAQABAoIBAFTNjxouIFYz+Qen
+Zo3NHCjewpyJLm7b75zrd6/SY39dag+QxnQUmkAK0BQJM5NX3lhSBEzuP4+OkHsU
+LNJ51mliqWZR2fDchDp8Jq/FYV4/UBM3bgDI64NONSCfwNk8+ZhUFJuy11Ppo6s0
+rwyv/53JXCQG4eoaAbZGjCuwJXdyGQKC6fl5H5oN6PasFXVuYp1IqXA8E5kqufuj
+FQzszHxmxtmANe+emZjaBxNPH3u/mSVUZboQ1sRmSQNjQ8pevCiwN7SRKS22BAL+
+KuMU3cJZcxoKtf4KQxjUpYPuN0Qv9vWS1RIGy1IxWnJsE+mtkDcEbj0oFlbPdviR
+Z3bYcikCgYEA6K9H8+vJO1jrVKLWEOuDYNndXUlfloVuiBBUyenh/OfL6D4Z7C4R
+fiE7WI4Sb7Gf9eA0s4+aKx1YxNp3RBvN9ApIUxVS0+sHFWNKRO04oXrRJfbH5M69
+MYYfB81csdT9ypJW+pbb7qUiR7lpLzijyXeuD5PAU/l2eGiscm3tW1MCgYEAvm+x
+MtZ6cbpNGn5OVLAGQ0EHa+RhrqfrGLlsaTKMV34Lp1zXcIhAr8mAHpyT8/SthL1N
+QD5fP6o5G77A+cJcz0mHLiBSTG2brx8thTrvt8ZNQDINKfySPrhZT27aZUK5Xvm1
+qWbC+X7SuhXP3D3HmB1VLT89YB09LgstM1R5uCkCgYB7wP3b1YPpdJl1IkYIKbpu
+QHFjtCqKu9zVsRnnaeUvxXjFxIG1A6t6EeKmbqmPjkEtXFmrRq0QUUNtL2RPbRpU
+uUNOLQEohM/3qB9QGXsNJ20la+NU5j/pnxPR6n9qdYWlv79S9/lxK5LX4tz2qIE0
+HdsNnd+kygEgeUt+cMjU0QKBgFdZyjDkemOiLe3CE9H6r9S3hlzx8/B2K3s6ykRy
+oDcdpODO0C9ZADrhtXfVIHRdPh5N6ppWQcBlJy7Xz5KAmaunMW9x+e3+tNOd/HZJ
+M13bguG4U5t3s+k7DBRIZ7rc4UR0S+R5M2PXzXb3vFFssRnQEprfkBp/LunozIHn
+9LEJAoGAWEzXrCAvBs6g4QU0/D3yMpjBZV9DQ3ndMC2osrkBWJnyUNg9p9mvwzgU
+CMwopkXH33YKazTiPaEPCBXtMibArYSS81ey3C4asCKFADiVelnU0yqWgx5PrM6D
+OSQGFJZO8TCTkiDrnq5w20bXyPJGbrAfcwavnL0xUIPGnLhuOZE=
+-----END RSA PRIVATE KEY-----
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/README.md b/Ark.Alliance.StartupCms.Ai.Backend/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..4d3d78223f7520394043a737d12be03b115a20d5
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/README.md
@@ -0,0 +1,293 @@
+# Ark.Alliance.StartupCms.AI.Backend
+
+
+
+
+
+
+
+
+**RESTful API Backend for Ark.Alliance.StartupCms.AI**
+
+*Express • TypeORM • JWT Auth • Multi-Provider AI • Team Management*
+
+
+
+---
+
+The **Backend** is a robust Node.js/Express application providing RESTful APIs for the AI-powered startup CMS ecosystem. It features TypeORM for database interactions, multi-provider AI services, JWT authentication, hierarchical team management, and comprehensive resume data handling.
+
+## 📦 Functional Capabilities
+
+The backend serves as the secure, intelligent core of the ecosystem.
+
+| Domain | Capability | Description | Code Reference |
+| :--- | :--- | :--- | :--- |
+| **API** | **REST Endpoints** | Structured controllers for Auth, Team, Resume, Projects, and AI. | `src/controllers/*.controller.ts` |
+| **Security** | **Authentication** | JWT-based auth with bcrypt hashing, RBAC, and Helmet headers. | `src/middleware/auth.middleware.ts` |
+| **AI** | **Multi-Provider AI** | Unified interface for OpenAI, Anthropic, and Google Gemini with prompt templates. | `src/services/ai.service.ts` |
+| **Team** | **Hierarchy Management** | Org chart with hierarchical relationships and reporting structure. | `src/services/collaborator.service.ts` |
+| **Resume** | **Profile System** | Comprehensive resume data: experiences, skills, education, languages, hobbies, domains. | `src/services/resume.service.ts` |
+| **Media** | **Asset Management** | Avatar uploads with base64 encoding and automatic synchronization. | `src/services/media.service.ts` |
+| **Data** | **High-Performance Persistence** | TypeORM with SQLite, indexed queries, and optimized entity relationships. | `src/database/entities/` |
+| **Tasks** | **Growth Tracking** | Task management with lessons learned and partial public visibility. | `src/services/task.service.ts` |
+| **DevOps** | **Auto-Seeding** | Automatic DB population with team members, skills, and sample data. | `src/database/seeds/seed.ts` |
+
+---
+
+## 🏗️ Project Structure
+
+```text
+Ark.Alliance.StartupCms.Ai.Backend/
+├── 📁 src/
+│ ├── config/ # Configuration modules
+│ │ ├── database.ts # TypeORM DataSource
+│ │ ├── swagger.config.ts # API documentation
+│ │ └── cors.config.ts # CORS whitelist
+│ │
+│ ├── controllers/ # Request handlers
+│ │ ├── auth.controller.ts # Authentication
+│ │ ├── collaborator.controller.ts # Team/Org Chart
+│ │ ├── resume.controller.ts # Resume Data API
+│ │ ├── project.controller.ts # Project CRUD
+│ │ ├── task.controller.ts # Task Management
+│ │ └── ai-profile.controller.ts # AI Profile Generation
+│ │
+│ ├── database/
+│ │ ├── entities/ # TypeORM entities with indexes
+│ │ │ ├── User.ts # User authentication
+│ │ │ ├── Collaborator.ts # Team members
+│ │ │ ├── Experience.ts # Work history
+│ │ │ ├── Skill.ts # Technical skills
+│ │ │ ├── Education.ts # Academic background
+│ │ │ ├── Language.ts # Language proficiency
+│ │ │ ├── Hobby.ts # Personal interests
+│ │ │ ├── BusinessDomain.ts # Industry expertise
+│ │ │ ├── Task.ts # Task tracking
+│ │ │ └── PromptTemplate.ts # AI prompt templates
+│ │ ├── seeds/ # Data seeding
+│ │ │ └── seeders/
+│ │ │ ├── organization.seeder.ts
+│ │ │ ├── bryan-ceo.seeder.ts
+│ │ │ ├── armand-architect.seeder.ts
+│ │ │ ├── radu-director.seeder.ts
+│ │ │ ├── mario-consultant.seeder.ts
+│ │ │ ├── lenny-csm.seeder.ts
+│ │ │ └── avatar.seeder.ts
+│ │ └── InitDbAsset/ # JSON seed data
+│ │
+│ ├── middleware/ # Express middleware
+│ │ ├── auth.middleware.ts # JWT verification
+│ │ └── error.middleware.ts # Global error handler
+│ │
+│ ├── services/ # Business logic
+│ │ ├── auth.service.ts # Authentication
+│ │ ├── collaborator.service.ts # Team hierarchy
+│ │ ├── resume.service.ts # Resume aggregation
+│ │ ├── ai-profile.service.ts # AI-assisted profile generation
+│ │ ├── task.service.ts # Task management
+│ │ └── prompt-template.service.ts # AI prompt management
+│ │
+│ └── index.ts # Entry point
+│
+├── 📁 Assets/
+│ └── Profil_Avatars/ # Team member avatars
+│
+└── 📄 data/
+ └── ark_portfolio.sqlite # SQLite database
+```
+
+---
+
+## 📐 Architecture
+
+### Request Flow
+
+```mermaid
+sequenceDiagram
+ participant Client
+ participant Express as Middleware Stack
+ participant Controller
+ participant Service
+ participant Repository
+ participant DB as Database
+
+ Client->>Express: HTTP Request
+ Express->>Express: CORS, Helmet, Auth
+ Express->>Controller: Route Handler
+ Controller->>Service: Business Logic
+ Service->>Repository: Data Access
+ Repository->>DB: Indexed Query
+ DB-->>Repository: Result
+ Repository-->>Service: Entity
+ Service-->>Controller: DTO
+ Controller-->>Express: Response
+ Express-->>Client: JSON
+```
+
+### Database Performance Optimizations
+
+All resume entities have **database indexes** on `userId` and `displayOrder` columns for optimal query performance:
+
+- `Experience`: `IDX_experience_userId`, `IDX_experience_displayOrder`
+- `Skill`: `IDX_skills_userId`, `IDX_skills_displayOrder`
+- `Education`: `IDX_education_userId`
+- `Language`: `IDX_languages_userId`, `IDX_languages_displayOrder`
+- `Hobby`: `IDX_hobbies_userId`, `IDX_hobbies_displayOrder`
+- `BusinessDomain`: `IDX_business_domains_userId`, `IDX_business_domains_displayOrder`
+
+---
+
+## 🔌 API Endpoints
+
+### Public Endpoints
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `GET` | `/api/team` | Get organization chart (hierarchical) |
+| `GET` | `/api/team/:id` | Get collaborator profile |
+| `GET` | `/api/resume` | Get resume data (defaults to Armand) |
+| `GET` | `/api/resume?userId=:id` | Get specific user's resume |
+| `GET` | `/api/projects` | List all projects |
+| `GET` | `/api/projects/:id` | Get project details |
+| `GET` | `/api/organization` | Get organization info |
+| `GET` | `/api/tasks` | List public tasks |
+
+### Authentication
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `POST` | `/api/auth/login` | User login |
+| `POST` | `/api/auth/logout` | User logout |
+| `GET` | `/api/auth/verify` | Verify JWT token |
+
+### Admin Endpoints (Protected)
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| `GET` | `/api/admin/projects` | List projects (admin) |
+| `POST` | `/api/admin/projects` | Create project |
+| `PUT` | `/api/admin/projects/:id` | Update project |
+| `DELETE` | `/api/admin/projects/:id` | Delete project |
+| `POST` | `/api/admin/media/upload` | Upload avatar/media |
+| `POST` | `/api/ai-profile/generate` | Generate AI profile |
+| `GET` | `/api/prompt-templates` | List AI prompt templates |
+
+---
+
+## ⚙️ Configuration
+
+### Environment Variables
+
+Create a `.env` file in the Backend root:
+
+```env
+# Server
+PORT=3085
+NODE_ENV=development
+
+# Database
+DATABASE_TYPE=sqlite
+DATABASE_NAME=ark_portfolio.sqlite
+
+# Authentication
+JWT_SECRET=your-256-bit-secret-key
+JWT_EXPIRES_IN=24h
+BCRYPT_ROUNDS=12
+ADMIN_KEY_CMS=your-admin-password
+
+# AI Providers
+OPENAI_API_KEY=sk-...
+ANTHROPIC_API_KEY=sk-ant-...
+GOOGLE_AI_API_KEY=...
+
+# CORS
+CORS_ORIGIN=http://localhost:3080
+
+# File Upload
+MAX_FILE_SIZE=10485760
+UPLOAD_PATH=./Assets/Profil_Avatars
+```
+
+---
+
+## 🚀 Usage
+
+### Prerequisites
+
+- Node.js v18+
+- `@arkalliance/startupcms-ai-share` built and available
+
+### Development Server
+
+```bash
+npm install
+npm run dev
+# Server runs on http://localhost:3085
+```
+
+### Production Build
+
+```bash
+npm run build
+npm start
+```
+
+### Database Seeding
+
+```bash
+npm run seed
+# Seeds organization, team members (Bryan, Armand, Radu, Mario, Lenny),
+# experiences, skills, languages, hobbies, business domains, and avatars
+```
+
+### API Documentation
+
+Once running, visit: [http://localhost:3085/api-docs](http://localhost:3085/api-docs)
+
+---
+
+## 🔒 Security Features
+
+| Feature | Implementation |
+|---------|----------------|
+| Password Hashing | bcrypt (12 rounds) |
+| JWT Tokens | HS256, 24h expiry |
+| Security Headers | Helmet.js |
+| CORS | Configured whitelist |
+| Input Validation | DTO validation |
+| Database Indexes | Performance + timing attack prevention |
+
+---
+
+## 🧪 Testing
+
+```bash
+# Run tests
+cd ../Ark.Alliance.StartupCms.Ai.Tests
+npm test -- --testPathPattern=Backend
+```
+
+---
+
+## 📚 Related Documentation
+
+| Document | Location | Purpose |
+|----------|----------|---------|
+| Main README | `../README.md` | Project overview, features, philosophy |
+| Share Layer | `../Ark.Alliance.StartupCms.Ai.Share/README.md` | DTOs, enums consumed by API |
+| UI Layer | `../Ark.Alliance.StartupCms.Ai.UI/README.md` | Frontend integration |
+| Tests Layer | `../Ark.Alliance.StartupCms.Ai.Tests/README.md` | Backend test patterns |
+
+---
+
+
+
+**Ark.Alliance.StartupCms.AI.Backend** — Part of the Ark Alliance Ecosystem
+
+
+Armand Richelet-Kleinberg © M2H.IO
+AI-assisted development with Anthropic Claude & Google Gemini
+
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/convert-imports.ps1 b/Ark.Alliance.StartupCms.Ai.Backend/convert-imports.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..2dcf11c36778340ed0184bc8448c22787fd25207
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/convert-imports.ps1
@@ -0,0 +1,46 @@
+# PowerShell script to convert package imports to relative imports
+# Converts '@ark/portfolio-share' to relative path based on file location
+
+$files = @(
+ "src/controllers/admin.controller.ts",
+ "src/database/entities/style-config.entity.ts",
+ "src/database/repositories/menu.repository.ts",
+ "src/services/admin-carousel.service.ts",
+ "src/services/admin-cv.service.ts",
+ "src/services/admin-media.service.ts",
+ "src/services/admin-menu.service.ts",
+ "src/services/admin-project.service.ts",
+ "src/services/admin-style.service.ts",
+ "src/services/admin-widget.service.ts",
+ "src/services/ai.service.ts",
+ "src/services/dashboard.service.ts",
+ "src/services/profile.service.ts"
+)
+
+foreach ($file in $files) {
+ $fullPath = "c:/Users/Criprtoswiss/source/repos/Ark.Portfolio/Ark.Portfolio.Backend/$file"
+
+ if (Test-Path $fullPath) {
+ $content = Get-Content $fullPath -Raw
+
+ # Calculate relative path from file to Share layer
+ # All these files are 3 levels deep from Backend root
+ $relativePath = if ($file -match "src/controllers/") {
+ "../../Ark.Portfolio.Share"
+ } elseif ($file -match "src/database/") {
+ "../../../Ark.Portfolio.Share"
+ } elseif ($file -match "src/services/") {
+ "../../Ark.Portfolio.Share"
+ } else {
+ "../../Ark.Portfolio.Share"
+ }
+
+ # Replace package import with relative import
+ $content = $content -replace "from '@ark/portfolio-share'", "from '$relativePath'"
+
+ Set-Content -Path $fullPath -Value $content -NoNewline
+ Write-Host "Updated: $file"
+ }
+}
+
+Write-Host "Done! Converted all files to use relative imports."
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/data/ark_portfolio.sqlite b/Ark.Alliance.StartupCms.Ai.Backend/data/ark_portfolio.sqlite
new file mode 100644
index 0000000000000000000000000000000000000000..eb7b93fb7b3c217a50905585bfd1a6db6b3f56ba
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/data/ark_portfolio.sqlite
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0bd68477ae4ecaaf62fab987191cd8049b980b8551f9fc405ab29846134a89ce
+size 2736128
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/docker-compose.yml b/Ark.Alliance.StartupCms.Ai.Backend/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..03811da5f56d10f572367e677894d572d734aeed
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/docker-compose.yml
@@ -0,0 +1,16 @@
+version: '3.8'
+services:
+ db:
+ image: postgres:15-alpine
+ container_name: ark_portfolio_db
+ environment:
+ POSTGRES_USER: postgres
+ POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: ark_portfolio
+ ports:
+ - "5432:5432"
+ volumes:
+ - postgres_data:/var/lib/postgresql/data
+
+volumes:
+ postgres_data:
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/final-fix-paths.ps1 b/Ark.Alliance.StartupCms.Ai.Backend/final-fix-paths.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..c4d1e4a8c7a12ab021ab64d9ebd2bcb0eda68a54
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/final-fix-paths.ps1
@@ -0,0 +1,27 @@
+# Final fix: Point to the actual index.ts file in Ark.Portfolio.Share
+
+Get-ChildItem -Path "src" -Recurse -Include *.ts | ForEach-Object {
+ $content = Get-Content $_.FullName -Raw
+
+ # Calculate correct relative path based on file depth
+ $relativePath = $_.FullName -replace [regex]::Escape("c:/Users/Criprtoswiss/source/repos/Ark.Portfolio/Ark.Portfolio.Backend/"), ""
+ $depth = ($relativePath -split "/").Count - 1
+
+ # Build correct path to Share index.ts
+ $shareIndexPath = switch ($depth) {
+ 2 { "../../Ark.Portfolio.Share/index" } # src/services/
+ 3 { "../../../Ark.Portfolio.Share/index" } # src/database/repositories/
+ default { "../../Ark.Portfolio.Share/index" }
+ }
+
+ # Replace the import
+ $newContent = $content -replace "from '\.\./\.\./Ark\.Portfolio\.Share'", "from '$shareIndexPath'"
+ $newContent = $newContent -replace "from '\.\./\.\./\.\./Ark\.Portfolio\.Share'", "from '$shareIndexPath'"
+
+ if ($newContent -ne $content) {
+ Set-Content -Path $_.FullName -Value $newContent -NoNewline
+ Write-Host "Fixed: $relativePath -> $shareIndexPath"
+ }
+}
+
+Write-Host "All paths now point to Ark.Portfolio.Share/index"
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/fix-paths.ps1 b/Ark.Alliance.StartupCms.Ai.Backend/fix-paths.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..73bd7f17c097403bc8a9bdaebdd490096828cada
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/fix-paths.ps1
@@ -0,0 +1,43 @@
+# Fix relative paths - services are 2 levels deep from src, need 3 ../ to reach parent
+# Structure: Ark.Portfolio.Backend/src/services/*.ts -> ../../../Ark.Portfolio.Share
+
+$filesToFix = @{
+ # Controllers: src/controllers/ -> need ../../
+ "src/controllers/admin.controller.ts" = "../../Ark.Portfolio.Share"
+
+ # Repositories: src/database/repositories/ -> need ../../../
+ "src/database/repositories/menu.repository.ts" = "../../../Ark.Portfolio.Share"
+
+ # Services: src/services/ -> need ../../
+ "src/services/admin-carousel.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/admin-cv.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/admin-media.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/admin-menu.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/admin-project.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/admin-style.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/admin-widget.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/ai.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/dashboard.service.ts" = "../../Ark.Portfolio.Share"
+ "src/services/profile.service.ts" = "../../Ark.Portfolio.Share"
+}
+
+foreach ($file in $filesToFix.Keys) {
+ $fullPath = "c:/Users/Criprtoswiss/source/repos/Ark.Portfolio/Ark.Portfolio.Backend/$file"
+ $correctPath = $filesToFix[$file]
+
+ if (Test-Path $fullPath) {
+ $content = Get-Content $fullPath -Raw
+
+ # Fix any incorrect paths
+ $content = $content -replace "from '\.\./\.\./Ark\.Portfolio\.Share'", "from '$correctPath'"
+ $content = $content -replace "from '\.\./\.\./\.\./Ark\.Portfolio\.Share'", "from '$correctPath'"
+
+ Set-Content -Path $fullPath -Value $content -NoNewline
+ Write-Host "Fixed: $file -> $correctPath"
+ }
+ else {
+ Write-Host "Not found: $file"
+ }
+}
+
+Write-Host "Done! All relative paths corrected."
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/package-lock.json b/Ark.Alliance.StartupCms.Ai.Backend/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..c412ad50e5086dd78595f424007a869eecc5ee96
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/package-lock.json
@@ -0,0 +1,5619 @@
+{
+ "name": "@ark-alliance-startupcms-ia/backend",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@ark-alliance-startupcms-ia/backend",
+ "version": "1.0.0",
+ "dependencies": {
+ "@types/archiver": "^7.0.0",
+ "@types/bcryptjs": "^2.4.6",
+ "@types/jsonwebtoken": "^9.0.10",
+ "@types/multer": "^2.0.0",
+ "@types/node-forge": "^1.3.14",
+ "@types/swagger-jsdoc": "^6.0.4",
+ "@types/swagger-ui-express": "^4.1.8",
+ "archiver": "^7.0.1",
+ "bcryptjs": "^3.0.3",
+ "class-transformer": "^0.5.1",
+ "class-validator": "^0.14.0",
+ "cors": "^2.8.5",
+ "dotenv": "^16.0.3",
+ "express": "^4.18.2",
+ "helmet": "^6.0.1",
+ "jsonwebtoken": "^9.0.3",
+ "multer": "^2.0.2",
+ "node-forge": "^1.3.3",
+ "pg": "^8.10.0",
+ "reflect-metadata": "^0.1.13",
+ "selfsigned": "^5.4.0",
+ "sqlite3": "^5.1.7",
+ "swagger-jsdoc": "^6.2.8",
+ "swagger-ui-express": "^5.0.1",
+ "typeorm": "^0.3.12"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.13",
+ "@types/express": "^4.17.17",
+ "@types/node": "^18.15.11",
+ "ts-node": "^10.9.2",
+ "ts-node-dev": "^2.0.0",
+ "tsconfig-paths": "^4.2.0",
+ "typescript": "^5.0.0"
+ }
+ },
+ "node_modules/@apidevtools/json-schema-ref-parser": {
+ "version": "9.1.2",
+ "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz",
+ "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==",
+ "license": "MIT",
+ "dependencies": {
+ "@jsdevtools/ono": "^7.1.3",
+ "@types/json-schema": "^7.0.6",
+ "call-me-maybe": "^1.0.1",
+ "js-yaml": "^4.1.0"
+ }
+ },
+ "node_modules/@apidevtools/openapi-schemas": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz",
+ "integrity": "sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@apidevtools/swagger-methods": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz",
+ "integrity": "sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==",
+ "license": "MIT"
+ },
+ "node_modules/@apidevtools/swagger-parser": {
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz",
+ "integrity": "sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g==",
+ "license": "MIT",
+ "dependencies": {
+ "@apidevtools/json-schema-ref-parser": "^9.0.6",
+ "@apidevtools/openapi-schemas": "^2.0.4",
+ "@apidevtools/swagger-methods": "^3.0.2",
+ "@jsdevtools/ono": "^7.1.3",
+ "call-me-maybe": "^1.0.1",
+ "z-schema": "^5.0.1"
+ },
+ "peerDependencies": {
+ "openapi-types": ">=7"
+ }
+ },
+ "node_modules/@cspotcode/source-map-support": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+ "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/trace-mapping": "0.3.9"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@gar/promisify": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
+ "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "license": "MIT"
+ },
+ "node_modules/@isaacs/cliui/node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@isaacs/cliui/node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+ "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.0.3",
+ "@jridgewell/sourcemap-codec": "^1.4.10"
+ }
+ },
+ "node_modules/@jsdevtools/ono": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
+ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
+ "license": "MIT"
+ },
+ "node_modules/@noble/hashes": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz",
+ "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@npmcli/fs": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz",
+ "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "@gar/promisify": "^1.0.1",
+ "semver": "^7.3.5"
+ }
+ },
+ "node_modules/@npmcli/move-file": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
+ "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
+ "deprecated": "This functionality has been moved to @npmcli/fs",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@npmcli/move-file/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "license": "MIT",
+ "optional": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@peculiar/asn1-cms": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.0.tgz",
+ "integrity": "sha512-2uZqP+ggSncESeUF/9Su8rWqGclEfEiz1SyU02WX5fUONFfkjzS2Z/F1Li0ofSmf4JqYXIOdCAZqIXAIBAT1OA==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "@peculiar/asn1-x509-attr": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-csr": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.0.tgz",
+ "integrity": "sha512-BeWIu5VpTIhfRysfEp73SGbwjjoLL/JWXhJ/9mo4vXnz3tRGm+NGm3KNcRzQ9VMVqwYS2RHlolz21svzRXIHPQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-ecc": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.0.tgz",
+ "integrity": "sha512-FF3LMGq6SfAOwUG2sKpPXblibn6XnEIKa+SryvUl5Pik+WR9rmRA3OCiwz8R3lVXnYnyRkSZsSLdml8H3UiOcw==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-pfx": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.0.tgz",
+ "integrity": "sha512-rtUvtf+tyKGgokHHmZzeUojRZJYPxoD/jaN1+VAB4kKR7tXrnDCA/RAWXAIhMJJC+7W27IIRGe9djvxKgsldCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-cms": "^2.6.0",
+ "@peculiar/asn1-pkcs8": "^2.6.0",
+ "@peculiar/asn1-rsa": "^2.6.0",
+ "@peculiar/asn1-schema": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-pkcs8": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.0.tgz",
+ "integrity": "sha512-KyQ4D8G/NrS7Fw3XCJrngxmjwO/3htnA0lL9gDICvEQ+GJ+EPFqldcJQTwPIdvx98Tua+WjkdKHSC0/Km7T+lA==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-pkcs9": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.0.tgz",
+ "integrity": "sha512-b78OQ6OciW0aqZxdzliXGYHASeCvvw5caqidbpQRYW2mBtXIX2WhofNXTEe7NyxTb0P6J62kAAWLwn0HuMF1Fw==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-cms": "^2.6.0",
+ "@peculiar/asn1-pfx": "^2.6.0",
+ "@peculiar/asn1-pkcs8": "^2.6.0",
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "@peculiar/asn1-x509-attr": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-rsa": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.0.tgz",
+ "integrity": "sha512-Nu4C19tsrTsCp9fDrH+sdcOKoVfdfoQQ7S3VqjJU6vedR7tY3RLkQ5oguOIB3zFW33USDUuYZnPEQYySlgha4w==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-schema": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz",
+ "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==",
+ "license": "MIT",
+ "dependencies": {
+ "asn1js": "^3.0.6",
+ "pvtsutils": "^1.3.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-x509": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.0.tgz",
+ "integrity": "sha512-uzYbPEpoQiBoTq0/+jZtpM6Gq6zADBx+JNFP3yqRgziWBxQ/Dt/HcuvRfm9zJTPdRcBqPNdaRHTVwpyiq6iNMA==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "pvtsutils": "^1.3.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/asn1-x509-attr": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.0.tgz",
+ "integrity": "sha512-MuIAXFX3/dc8gmoZBkwJWxUWOSvG4MMDntXhrOZpJVMkYX+MYc/rUAU2uJOved9iJEoiUx7//3D8oG83a78UJA==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "asn1js": "^3.0.6",
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/@peculiar/x509": {
+ "version": "1.14.2",
+ "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.2.tgz",
+ "integrity": "sha512-r2w1Hg6pODDs0zfAKHkSS5HLkOLSeburtcgwvlLLWWCixw+MmW3U6kD5ddyvc2Y2YdbGuVwCF2S2ASoU1cFAag==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/asn1-cms": "^2.6.0",
+ "@peculiar/asn1-csr": "^2.6.0",
+ "@peculiar/asn1-ecc": "^2.6.0",
+ "@peculiar/asn1-pkcs9": "^2.6.0",
+ "@peculiar/asn1-rsa": "^2.6.0",
+ "@peculiar/asn1-schema": "^2.6.0",
+ "@peculiar/asn1-x509": "^2.6.0",
+ "pvtsutils": "^1.3.6",
+ "reflect-metadata": "^0.2.2",
+ "tslib": "^2.8.1",
+ "tsyringe": "^4.10.0"
+ },
+ "engines": {
+ "node": ">=22.0.0"
+ }
+ },
+ "node_modules/@peculiar/x509/node_modules/reflect-metadata": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
+ "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@scarf/scarf": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz",
+ "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/@sqltools/formatter": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz",
+ "integrity": "sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==",
+ "license": "MIT"
+ },
+ "node_modules/@tootallnate/once": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/@tsconfig/node10": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
+ "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node12": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
+ "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node14": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
+ "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@tsconfig/node16": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
+ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/archiver": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-7.0.0.tgz",
+ "integrity": "sha512-/3vwGwx9n+mCQdYZ2IKGGHEFL30I96UgBlk8EtRDDFQ9uxM1l4O5Ci6r00EMAkiDaTqD9DQ6nVrWRICnBPtzzg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/readdir-glob": "*"
+ }
+ },
+ "node_modules/@types/bcryptjs": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz",
+ "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.6",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
+ "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/cors": {
+ "version": "2.8.19",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
+ "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.25",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz",
+ "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.33",
+ "@types/qs": "*",
+ "@types/serve-static": "^1"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.19.7",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz",
+ "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*",
+ "@types/send": "*"
+ }
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
+ "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/jsonwebtoken": {
+ "version": "9.0.10",
+ "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz",
+ "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/ms": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
+ "license": "MIT"
+ },
+ "node_modules/@types/ms": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
+ "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/multer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.0.0.tgz",
+ "integrity": "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "18.19.130",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
+ "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/node-forge": {
+ "version": "1.3.14",
+ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz",
+ "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/qs": {
+ "version": "6.14.0",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
+ "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/readdir-glob": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@types/readdir-glob/-/readdir-glob-1.1.5.tgz",
+ "integrity": "sha512-raiuEPUYqXu+nvtY2Pe8s8FEmZ3x5yAH4VkLdihcPdalvsHltomrRC9BzuStrJ9yk06470hS0Crw0f1pXqD+Hg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/send": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
+ "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.15.10",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz",
+ "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/http-errors": "*",
+ "@types/node": "*",
+ "@types/send": "<1"
+ }
+ },
+ "node_modules/@types/serve-static/node_modules/@types/send": {
+ "version": "0.17.6",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz",
+ "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/strip-json-comments": {
+ "version": "0.0.30",
+ "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz",
+ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/swagger-jsdoc": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/@types/swagger-jsdoc/-/swagger-jsdoc-6.0.4.tgz",
+ "integrity": "sha512-W+Xw5epcOZrF/AooUM/PccNMSAFOKWZA5dasNyMujTwsBkU74njSJBpvCCJhHAJ95XRMzQrrW844Btu0uoetwQ==",
+ "license": "MIT"
+ },
+ "node_modules/@types/swagger-ui-express": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.8.tgz",
+ "integrity": "sha512-AhZV8/EIreHFmBV5wAs0gzJUNq9JbbSXgJLQubCC0jtIo6prnI9MIRRxnU4MZX9RB9yXxF1V4R7jtLl/Wcj31g==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/validator": {
+ "version": "13.15.10",
+ "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.10.tgz",
+ "integrity": "sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==",
+ "license": "MIT"
+ },
+ "node_modules/abbrev": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "license": "MIT",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "devOptional": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+ "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/agent-base/node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/agent-base/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/agentkeepalive": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
+ "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "humanize-ms": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/aggregate-error": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+ "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/ansis": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.2.0.tgz",
+ "integrity": "sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/app-root-path": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.1.0.tgz",
+ "integrity": "sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/append-field": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
+ "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==",
+ "license": "MIT"
+ },
+ "node_modules/aproba": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz",
+ "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/archiver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
+ "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
+ "license": "MIT",
+ "dependencies": {
+ "archiver-utils": "^5.0.2",
+ "async": "^3.2.4",
+ "buffer-crc32": "^1.0.0",
+ "readable-stream": "^4.0.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^3.0.0",
+ "zip-stream": "^6.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/archiver-utils": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
+ "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
+ "license": "MIT",
+ "dependencies": {
+ "glob": "^10.0.0",
+ "graceful-fs": "^4.2.0",
+ "is-stream": "^2.0.1",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.17.15",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/glob": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/archiver/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/archiver/node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/archiver/node_modules/tar-stream": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
+ "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
+ "license": "MIT",
+ "dependencies": {
+ "b4a": "^1.6.4",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ },
+ "node_modules/are-we-there-yet": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
+ "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==",
+ "deprecated": "This package is no longer supported.",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/arg": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+ "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "license": "Python-2.0"
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
+ "license": "MIT"
+ },
+ "node_modules/asn1js": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz",
+ "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "pvtsutils": "^1.3.6",
+ "pvutils": "^1.1.3",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "license": "MIT"
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "license": "MIT",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/b4a": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz",
+ "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "license": "MIT"
+ },
+ "node_modules/bare-events": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
+ "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "bare-abort-controller": "*"
+ },
+ "peerDependenciesMeta": {
+ "bare-abort-controller": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/bcryptjs": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz",
+ "integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==",
+ "license": "BSD-3-Clause",
+ "bin": {
+ "bcrypt": "bin/bcrypt"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "license": "MIT",
+ "dependencies": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "node_modules/bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.4",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz",
+ "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "content-type": "~1.0.5",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "~1.2.0",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.4.24",
+ "on-finished": "~2.4.1",
+ "qs": "~6.14.0",
+ "raw-body": "~2.5.3",
+ "type-is": "~1.6.18",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
+ "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "license": "MIT"
+ },
+ "node_modules/busboy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+ "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "dependencies": {
+ "streamsearch": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=10.16.0"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/bytestreamjs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz",
+ "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/cacache": {
+ "version": "15.3.0",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz",
+ "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "@npmcli/fs": "^1.0.0",
+ "@npmcli/move-file": "^1.0.1",
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "glob": "^7.1.4",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.1",
+ "minipass-collect": "^1.0.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.2",
+ "mkdirp": "^1.0.3",
+ "p-map": "^4.0.0",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^3.0.2",
+ "ssri": "^8.0.1",
+ "tar": "^6.0.2",
+ "unique-filename": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/cacache/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "license": "MIT",
+ "optional": true,
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz",
+ "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.0",
+ "es-define-property": "^1.0.0",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/call-me-maybe": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.2.tgz",
+ "integrity": "sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==",
+ "license": "MIT"
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/class-transformer": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
+ "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
+ "license": "MIT"
+ },
+ "node_modules/class-validator": {
+ "version": "0.14.3",
+ "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.3.tgz",
+ "integrity": "sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/validator": "^13.15.3",
+ "libphonenumber-js": "^1.11.1",
+ "validator": "^13.15.20"
+ }
+ },
+ "node_modules/clean-stack": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+ "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT"
+ },
+ "node_modules/color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+ "license": "ISC",
+ "optional": true,
+ "bin": {
+ "color-support": "bin.js"
+ }
+ },
+ "node_modules/commander": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz",
+ "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/compress-commons": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
+ "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
+ "license": "MIT",
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "crc32-stream": "^6.0.0",
+ "is-stream": "^2.0.1",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/compress-commons/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/compress-commons/node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "license": "MIT"
+ },
+ "node_modules/concat-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+ "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+ "engines": [
+ "node >= 6.0"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.0.2",
+ "typedarray": "^0.0.6"
+ }
+ },
+ "node_modules/console-control-strings": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
+ "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
+ "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
+ "license": "MIT"
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "license": "MIT"
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/crc-32": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+ "license": "Apache-2.0",
+ "bin": {
+ "crc32": "bin/crc32.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/crc32-stream": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz",
+ "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==",
+ "license": "MIT",
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/crc32-stream/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/crc32-stream/node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/create-require": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
+ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/dayjs": {
+ "version": "1.11.19",
+ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
+ "integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/decompress-response": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+ "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-response": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/dedent": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz",
+ "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "babel-plugin-macros": "^3.1.0"
+ },
+ "peerDependenciesMeta": {
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/delegates": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+ "devOptional": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.6.1",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
+ "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/dynamic-dedupe": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz",
+ "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "xtend": "^4.0.0"
+ }
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "license": "MIT"
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "license": "MIT"
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/encoding": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "iconv-lite": "^0.6.2"
+ }
+ },
+ "node_modules/encoding/node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+ "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/env-paths": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+ "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/err-code": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+ "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/events-universal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
+ "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.7.0"
+ }
+ },
+ "node_modules/expand-template": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
+ "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
+ "license": "(MIT OR WTFPL)",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/express": {
+ "version": "4.22.1",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
+ "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "~1.20.3",
+ "content-disposition": "~0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "~0.7.1",
+ "cookie-signature": "~1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.3.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.0",
+ "merge-descriptors": "1.0.3",
+ "methods": "~1.1.2",
+ "on-finished": "~2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "~0.1.12",
+ "proxy-addr": "~2.0.7",
+ "qs": "~6.14.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "~0.19.0",
+ "serve-static": "~1.16.2",
+ "setprototypeof": "1.2.0",
+ "statuses": "~2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "license": "MIT"
+ },
+ "node_modules/file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "license": "MIT"
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz",
+ "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "~2.0.2",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/for-each": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
+ "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/foreground-child/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "license": "MIT"
+ },
+ "node_modules/fs-minipass": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+ "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "license": "ISC"
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gauge": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
+ "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
+ "deprecated": "This package is no longer supported.",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "aproba": "^1.0.3 || ^2.0.0",
+ "color-support": "^1.1.3",
+ "console-control-strings": "^1.1.0",
+ "has-unicode": "^2.0.1",
+ "signal-exit": "^3.0.7",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wide-align": "^1.1.5"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/github-from-package": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
+ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
+ "license": "MIT"
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "devOptional": true,
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "license": "MIT",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-unicode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+ "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/helmet": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/helmet/-/helmet-6.2.0.tgz",
+ "integrity": "sha512-DWlwuXLLqbrIOltR6tFQXShj/+7Cyp0gLi6uAb8qMdFh/YBBFbKSgQ6nbXmScYd8emMctuthmgIa7tUfo9Rtyg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/http-cache-semantics": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
+ "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
+ "license": "BSD-2-Clause",
+ "optional": true
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
+ "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~2.0.0",
+ "inherits": "~2.0.4",
+ "setprototypeof": "~1.2.0",
+ "statuses": "~2.0.2",
+ "toidentifier": "~1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+ "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@tootallnate/once": "1",
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/http-proxy-agent/node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/http-proxy-agent/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+ "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "agent-base": "6",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/https-proxy-agent/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.0.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/infer-owner": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+ "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "license": "ISC"
+ },
+ "node_modules/ip-address": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz",
+ "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-lambda": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
+ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz",
+ "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==",
+ "license": "MIT",
+ "dependencies": {
+ "which-typed-array": "^1.1.16"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "license": "ISC"
+ },
+ "node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+ "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz",
+ "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==",
+ "license": "MIT",
+ "dependencies": {
+ "jws": "^4.0.1",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/jwa": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
+ "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-equal-constant-time": "^1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz",
+ "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==",
+ "license": "MIT",
+ "dependencies": {
+ "jwa": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/lazystream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.6.3"
+ }
+ },
+ "node_modules/lazystream/node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "license": "MIT"
+ },
+ "node_modules/lazystream/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/lazystream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "license": "MIT"
+ },
+ "node_modules/lazystream/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/libphonenumber-js": {
+ "version": "1.12.33",
+ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.33.tgz",
+ "integrity": "sha512-r9kw4OA6oDO4dPXkOrXTkArQAafIKAU71hChInV4FxZ69dxCfbwQGDPzqR5/vea94wU705/3AZroEbSoeVWrQw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
+ "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.",
+ "license": "MIT"
+ },
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==",
+ "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead.",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.mergewith": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
+ "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+ "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "devOptional": true,
+ "license": "ISC"
+ },
+ "node_modules/make-fetch-happen": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
+ "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "agentkeepalive": "^4.1.3",
+ "cacache": "^15.2.0",
+ "http-cache-semantics": "^4.1.0",
+ "http-proxy-agent": "^4.0.1",
+ "https-proxy-agent": "^5.0.0",
+ "is-lambda": "^1.0.1",
+ "lru-cache": "^6.0.0",
+ "minipass": "^3.1.3",
+ "minipass-collect": "^1.0.2",
+ "minipass-fetch": "^1.3.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.4",
+ "negotiator": "^0.6.2",
+ "promise-retry": "^2.0.1",
+ "socks-proxy-agent": "^6.0.0",
+ "ssri": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
+ "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-response": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+ "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
+ "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minipass-collect": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
+ "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minipass-fetch": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz",
+ "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.1.0",
+ "minipass-sized": "^1.0.3",
+ "minizlib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "optionalDependencies": {
+ "encoding": "^0.1.12"
+ }
+ },
+ "node_modules/minipass-flush": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
+ "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/minipass-pipeline": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+ "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minipass-sized": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
+ "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+ "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^3.0.0",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+ "license": "MIT"
+ },
+ "node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "license": "MIT"
+ },
+ "node_modules/multer": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz",
+ "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==",
+ "license": "MIT",
+ "dependencies": {
+ "append-field": "^1.0.0",
+ "busboy": "^1.6.0",
+ "concat-stream": "^2.0.0",
+ "mkdirp": "^0.5.6",
+ "object-assign": "^4.1.1",
+ "type-is": "^1.6.18",
+ "xtend": "^4.0.2"
+ },
+ "engines": {
+ "node": ">= 10.16.0"
+ }
+ },
+ "node_modules/napi-build-utils": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
+ "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/node-abi": {
+ "version": "3.85.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz",
+ "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==",
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "license": "MIT"
+ },
+ "node_modules/node-forge": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz",
+ "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==",
+ "license": "(BSD-3-Clause OR GPL-2.0)",
+ "engines": {
+ "node": ">= 6.13.0"
+ }
+ },
+ "node_modules/node-gyp": {
+ "version": "8.4.1",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
+ "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "env-paths": "^2.2.0",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.6",
+ "make-fetch-happen": "^9.1.0",
+ "nopt": "^5.0.0",
+ "npmlog": "^6.0.0",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.5",
+ "tar": "^6.1.2",
+ "which": "^2.0.2"
+ },
+ "bin": {
+ "node-gyp": "bin/node-gyp.js"
+ },
+ "engines": {
+ "node": ">= 10.12.0"
+ }
+ },
+ "node_modules/nopt": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+ "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npmlog": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz",
+ "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==",
+ "deprecated": "This package is no longer supported.",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "are-we-there-yet": "^3.0.0",
+ "console-control-strings": "^1.1.0",
+ "gauge": "^4.0.3",
+ "set-blocking": "^2.0.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.4",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+ "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/openapi-types": {
+ "version": "12.1.3",
+ "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz",
+ "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/p-map": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+ "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
+ },
+ "node_modules/path-scurry/node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "0.1.12",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
+ "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
+ "license": "MIT"
+ },
+ "node_modules/pg": {
+ "version": "8.16.3",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz",
+ "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "pg-connection-string": "^2.9.1",
+ "pg-pool": "^3.10.1",
+ "pg-protocol": "^1.10.3",
+ "pg-types": "2.2.0",
+ "pgpass": "1.0.5"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "optionalDependencies": {
+ "pg-cloudflare": "^1.2.7"
+ },
+ "peerDependencies": {
+ "pg-native": ">=3.0.1"
+ },
+ "peerDependenciesMeta": {
+ "pg-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pg-cloudflare": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz",
+ "integrity": "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/pg-connection-string": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.9.1.tgz",
+ "integrity": "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==",
+ "license": "MIT"
+ },
+ "node_modules/pg-int8": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
+ "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/pg-pool": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.10.1.tgz",
+ "integrity": "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "pg": ">=8.0"
+ }
+ },
+ "node_modules/pg-protocol": {
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.10.3.tgz",
+ "integrity": "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==",
+ "license": "MIT"
+ },
+ "node_modules/pg-types": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
+ "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
+ "license": "MIT",
+ "dependencies": {
+ "pg-int8": "1.0.1",
+ "postgres-array": "~2.0.0",
+ "postgres-bytea": "~1.0.0",
+ "postgres-date": "~1.0.4",
+ "postgres-interval": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/pgpass": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
+ "license": "MIT",
+ "dependencies": {
+ "split2": "^4.1.0"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pkijs": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.3.3.tgz",
+ "integrity": "sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@noble/hashes": "1.4.0",
+ "asn1js": "^3.0.6",
+ "bytestreamjs": "^2.0.1",
+ "pvtsutils": "^1.3.6",
+ "pvutils": "^1.1.3",
+ "tslib": "^2.8.1"
+ },
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz",
+ "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/postgres-array": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
+ "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postgres-bytea": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
+ "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-date": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
+ "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-interval": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
+ "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "xtend": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/prebuild-install": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
+ "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^2.0.0",
+ "expand-template": "^2.0.3",
+ "github-from-package": "0.0.0",
+ "minimist": "^1.2.3",
+ "mkdirp-classic": "^0.5.3",
+ "napi-build-utils": "^2.0.0",
+ "node-abi": "^3.3.0",
+ "pump": "^3.0.0",
+ "rc": "^1.2.7",
+ "simple-get": "^4.0.0",
+ "tar-fs": "^2.0.0",
+ "tunnel-agent": "^0.6.0"
+ },
+ "bin": {
+ "prebuild-install": "bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "license": "MIT"
+ },
+ "node_modules/promise-inflight": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+ "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/promise-retry": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+ "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "err-code": "^2.0.2",
+ "retry": "^0.12.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/pump": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
+ "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/pvtsutils": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
+ "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.8.1"
+ }
+ },
+ "node_modules/pvutils": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz",
+ "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16.0.0"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.14.1",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
+ "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
+ "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "~3.1.2",
+ "http-errors": "~2.0.1",
+ "iconv-lite": "~0.4.24",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+ "dependencies": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "bin": {
+ "rc": "cli.js"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/readdir-glob": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "minimatch": "^5.1.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/reflect-metadata": {
+ "version": "0.1.14",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz",
+ "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.11",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
+ "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.1",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
+ "node_modules/selfsigned": {
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.4.0.tgz",
+ "integrity": "sha512-Yn8qZOOJv+NhcGY19iC+ngW6hlUCNpvWEkrKllXNhmkLgR9fcErm8EqZ/wev7/tiwjKC9qj17Fa/PtBNzb6q8g==",
+ "license": "MIT",
+ "dependencies": {
+ "@peculiar/x509": "^1.14.2",
+ "pkijs": "^3.3.3"
+ },
+ "engines": {
+ "node": ">=15.6.0"
+ }
+ },
+ "node_modules/semver": {
+ "version": "7.7.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz",
+ "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "~0.5.2",
+ "http-errors": "~2.0.1",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "~2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "~2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/serve-static": {
+ "version": "1.16.3",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz",
+ "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~2.0.0",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "~0.19.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "license": "MIT",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "license": "ISC"
+ },
+ "node_modules/sha.js": {
+ "version": "2.4.12",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz",
+ "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==",
+ "license": "(MIT AND BSD-3-Clause)",
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "safe-buffer": "^5.2.1",
+ "to-buffer": "^1.2.0"
+ },
+ "bin": {
+ "sha.js": "bin.js"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+ "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-map": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+ "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3",
+ "side-channel-map": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/simple-concat": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+ "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/simple-get": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+ "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "decompress-response": "^6.0.0",
+ "once": "^1.3.1",
+ "simple-concat": "^1.0.0"
+ }
+ },
+ "node_modules/smart-buffer": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 6.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks": {
+ "version": "2.8.7",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz",
+ "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ip-address": "^10.0.1",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz",
+ "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "agent-base": "^6.0.2",
+ "debug": "^4.3.3",
+ "socks": "^2.6.2"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/socks-proxy-agent/node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/socks-proxy-agent/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/sql-highlight": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/sql-highlight/-/sql-highlight-6.1.0.tgz",
+ "integrity": "sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA==",
+ "funding": [
+ "https://github.com/scriptcoded/sql-highlight?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/scriptcoded"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/sqlite3": {
+ "version": "5.1.7",
+ "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz",
+ "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==",
+ "hasInstallScript": true,
+ "license": "BSD-3-Clause",
+ "peer": true,
+ "dependencies": {
+ "bindings": "^1.5.0",
+ "node-addon-api": "^7.0.0",
+ "prebuild-install": "^7.1.1",
+ "tar": "^6.1.11"
+ },
+ "optionalDependencies": {
+ "node-gyp": "8.x"
+ },
+ "peerDependencies": {
+ "node-gyp": "8.x"
+ },
+ "peerDependenciesMeta": {
+ "node-gyp": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ssri": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
+ "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "minipass": "^3.1.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/streamsearch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/streamx": {
+ "version": "2.23.0",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz",
+ "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==",
+ "license": "MIT",
+ "dependencies": {
+ "events-universal": "^1.0.0",
+ "fast-fifo": "^1.3.2",
+ "text-decoder": "^1.1.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/swagger-jsdoc": {
+ "version": "6.2.8",
+ "resolved": "https://registry.npmjs.org/swagger-jsdoc/-/swagger-jsdoc-6.2.8.tgz",
+ "integrity": "sha512-VPvil1+JRpmJ55CgAtn8DIcpBs0bL5L3q5bVQvF4tAW/k/9JYSj7dCpaYCAv5rufe0vcCbBRQXGvzpkWjvLklQ==",
+ "license": "MIT",
+ "dependencies": {
+ "commander": "6.2.0",
+ "doctrine": "3.0.0",
+ "glob": "7.1.6",
+ "lodash.mergewith": "^4.6.2",
+ "swagger-parser": "^10.0.3",
+ "yaml": "2.0.0-1"
+ },
+ "bin": {
+ "swagger-jsdoc": "bin/swagger-jsdoc.js"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/swagger-jsdoc/node_modules/glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "license": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/swagger-parser": {
+ "version": "10.0.3",
+ "resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-10.0.3.tgz",
+ "integrity": "sha512-nF7oMeL4KypldrQhac8RyHerJeGPD1p2xDh900GPvc+Nk7nWP6jX2FcC7WmkinMoAmoO774+AFXcWsW8gMWEIg==",
+ "license": "MIT",
+ "dependencies": {
+ "@apidevtools/swagger-parser": "10.0.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/swagger-ui-dist": {
+ "version": "5.31.0",
+ "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.31.0.tgz",
+ "integrity": "sha512-zSUTIck02fSga6rc0RZP3b7J7wgHXwLea8ZjgLA3Vgnb8QeOl3Wou2/j5QkzSGeoz6HusP/coYuJl33aQxQZpg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@scarf/scarf": "=1.4.0"
+ }
+ },
+ "node_modules/swagger-ui-express": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-5.0.1.tgz",
+ "integrity": "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==",
+ "license": "MIT",
+ "dependencies": {
+ "swagger-ui-dist": ">=5.0.0"
+ },
+ "engines": {
+ "node": ">= v0.10.32"
+ },
+ "peerDependencies": {
+ "express": ">=4.0.0 || >=5.0.0-beta"
+ }
+ },
+ "node_modules/tar": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
+ "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==",
+ "license": "ISC",
+ "dependencies": {
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.0.0",
+ "minipass": "^5.0.0",
+ "minizlib": "^2.1.1",
+ "mkdirp": "^1.0.3",
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+ "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+ "license": "MIT",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-fs/node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "license": "ISC"
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar/node_modules/minipass": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
+ "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/text-decoder": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
+ "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.6.4"
+ }
+ },
+ "node_modules/to-buffer": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz",
+ "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==",
+ "license": "MIT",
+ "dependencies": {
+ "isarray": "^2.0.5",
+ "safe-buffer": "^5.2.1",
+ "typed-array-buffer": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
+ "node_modules/ts-node": {
+ "version": "10.9.2",
+ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
+ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
+ "devOptional": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@cspotcode/source-map-support": "^0.8.0",
+ "@tsconfig/node10": "^1.0.7",
+ "@tsconfig/node12": "^1.0.7",
+ "@tsconfig/node14": "^1.0.0",
+ "@tsconfig/node16": "^1.0.2",
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.1.1",
+ "arg": "^4.1.0",
+ "create-require": "^1.1.0",
+ "diff": "^4.0.1",
+ "make-error": "^1.1.1",
+ "v8-compile-cache-lib": "^3.0.1",
+ "yn": "3.1.1"
+ },
+ "bin": {
+ "ts-node": "dist/bin.js",
+ "ts-node-cwd": "dist/bin-cwd.js",
+ "ts-node-esm": "dist/bin-esm.js",
+ "ts-node-script": "dist/bin-script.js",
+ "ts-node-transpile-only": "dist/bin-transpile.js",
+ "ts-script": "dist/bin-script-deprecated.js"
+ },
+ "peerDependencies": {
+ "@swc/core": ">=1.2.50",
+ "@swc/wasm": ">=1.2.50",
+ "@types/node": "*",
+ "typescript": ">=2.7"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "@swc/wasm": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ts-node-dev": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz",
+ "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.1",
+ "dynamic-dedupe": "^0.3.0",
+ "minimist": "^1.2.6",
+ "mkdirp": "^1.0.4",
+ "resolve": "^1.0.0",
+ "rimraf": "^2.6.1",
+ "source-map-support": "^0.5.12",
+ "tree-kill": "^1.2.2",
+ "ts-node": "^10.4.0",
+ "tsconfig": "^7.0.0"
+ },
+ "bin": {
+ "ts-node-dev": "lib/bin.js",
+ "tsnd": "lib/bin.js"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "*",
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ts-node-dev/node_modules/mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ts-node-dev/node_modules/rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/tsconfig": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz",
+ "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/strip-bom": "^3.0.0",
+ "@types/strip-json-comments": "0.0.30",
+ "strip-bom": "^3.0.0",
+ "strip-json-comments": "^2.0.0"
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
+ "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "json5": "^2.2.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
+ },
+ "node_modules/tsyringe": {
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz",
+ "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^1.9.3"
+ },
+ "engines": {
+ "node": ">= 6.0.0"
+ }
+ },
+ "node_modules/tsyringe/node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "license": "0BSD"
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "license": "MIT",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bound": "^1.0.3",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+ "license": "MIT"
+ },
+ "node_modules/typeorm": {
+ "version": "0.3.28",
+ "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.28.tgz",
+ "integrity": "sha512-6GH7wXhtfq2D33ZuRXYwIsl/qM5685WZcODZb7noOOcRMteM9KF2x2ap3H0EBjnSV0VO4gNAfJT5Ukp0PkOlvg==",
+ "license": "MIT",
+ "dependencies": {
+ "@sqltools/formatter": "^1.2.5",
+ "ansis": "^4.2.0",
+ "app-root-path": "^3.1.0",
+ "buffer": "^6.0.3",
+ "dayjs": "^1.11.19",
+ "debug": "^4.4.3",
+ "dedent": "^1.7.0",
+ "dotenv": "^16.6.1",
+ "glob": "^10.5.0",
+ "reflect-metadata": "^0.2.2",
+ "sha.js": "^2.4.12",
+ "sql-highlight": "^6.1.0",
+ "tslib": "^2.8.1",
+ "uuid": "^11.1.0",
+ "yargs": "^17.7.2"
+ },
+ "bin": {
+ "typeorm": "cli.js",
+ "typeorm-ts-node-commonjs": "cli-ts-node-commonjs.js",
+ "typeorm-ts-node-esm": "cli-ts-node-esm.js"
+ },
+ "engines": {
+ "node": ">=16.13.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/typeorm"
+ },
+ "peerDependencies": {
+ "@google-cloud/spanner": "^5.18.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+ "@sap/hana-client": "^2.14.22",
+ "better-sqlite3": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0",
+ "ioredis": "^5.0.4",
+ "mongodb": "^5.8.0 || ^6.0.0",
+ "mssql": "^9.1.1 || ^10.0.0 || ^11.0.0 || ^12.0.0",
+ "mysql2": "^2.2.5 || ^3.0.1",
+ "oracledb": "^6.3.0",
+ "pg": "^8.5.1",
+ "pg-native": "^3.0.0",
+ "pg-query-stream": "^4.0.0",
+ "redis": "^3.1.1 || ^4.0.0 || ^5.0.14",
+ "sql.js": "^1.4.0",
+ "sqlite3": "^5.0.3",
+ "ts-node": "^10.7.0",
+ "typeorm-aurora-data-api-driver": "^2.0.0 || ^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@google-cloud/spanner": {
+ "optional": true
+ },
+ "@sap/hana-client": {
+ "optional": true
+ },
+ "better-sqlite3": {
+ "optional": true
+ },
+ "ioredis": {
+ "optional": true
+ },
+ "mongodb": {
+ "optional": true
+ },
+ "mssql": {
+ "optional": true
+ },
+ "mysql2": {
+ "optional": true
+ },
+ "oracledb": {
+ "optional": true
+ },
+ "pg": {
+ "optional": true
+ },
+ "pg-native": {
+ "optional": true
+ },
+ "pg-query-stream": {
+ "optional": true
+ },
+ "redis": {
+ "optional": true
+ },
+ "sql.js": {
+ "optional": true
+ },
+ "sqlite3": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ },
+ "typeorm-aurora-data-api-driver": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typeorm/node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/typeorm/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/typeorm/node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/typeorm/node_modules/glob": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz",
+ "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==",
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/typeorm/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/typeorm/node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/typeorm/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/typeorm/node_modules/reflect-metadata": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
+ "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "license": "MIT"
+ },
+ "node_modules/unique-filename": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+ "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "node_modules/unique-slug": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+ "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "license": "MIT"
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
+ "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/esm/bin/uuid"
+ }
+ },
+ "node_modules/v8-compile-cache-lib": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+ "devOptional": true,
+ "license": "MIT"
+ },
+ "node_modules/validator": {
+ "version": "13.15.26",
+ "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.26.tgz",
+ "integrity": "sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.19",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz",
+ "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==",
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
+ "for-each": "^0.3.5",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/wide-align": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
+ "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
+ "license": "ISC",
+ "optional": true,
+ "dependencies": {
+ "string-width": "^1.0.2 || 2 || 3 || 4"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "license": "ISC"
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+ "license": "ISC"
+ },
+ "node_modules/yaml": {
+ "version": "2.0.0-1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.0.0-1.tgz",
+ "integrity": "sha512-W7h5dEhywMKenDJh2iX/LABkbFnBxasD27oyXWDS/feDsxiw0dD5ncXdYXgkvAsXIY2MpW/ZKkr9IU30DBdMNQ==",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yn": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+ "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/z-schema": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/z-schema/-/z-schema-5.0.5.tgz",
+ "integrity": "sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==",
+ "license": "MIT",
+ "dependencies": {
+ "lodash.get": "^4.4.2",
+ "lodash.isequal": "^4.5.0",
+ "validator": "^13.7.0"
+ },
+ "bin": {
+ "z-schema": "bin/z-schema"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "commander": "^9.4.1"
+ }
+ },
+ "node_modules/z-schema/node_modules/commander": {
+ "version": "9.5.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
+ "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": "^12.20.0 || >=14"
+ }
+ },
+ "node_modules/zip-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz",
+ "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==",
+ "license": "MIT",
+ "dependencies": {
+ "archiver-utils": "^5.0.0",
+ "compress-commons": "^6.0.2",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/zip-stream/node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/zip-stream/node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ }
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/package.json b/Ark.Alliance.StartupCms.Ai.Backend/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c4724d12c3c5e7a7792926b95bd5083233b9a5d
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/package.json
@@ -0,0 +1,48 @@
+{
+ "name": "@ark-alliance-startupcms-ia/backend",
+ "version": "1.0.0",
+ "description": "Backend for Ark Portfolio",
+ "main": "dist/index.js",
+ "scripts": {
+ "start": "node dist/index.js",
+ "dev": "ts-node-dev -r tsconfig-paths/register --respawn --transpile-only src/index.ts",
+ "build": "tsc",
+ "seed": "ts-node -r tsconfig-paths/register src/database/seeds/seed.ts"
+ },
+ "dependencies": {
+ "@types/archiver": "^7.0.0",
+ "@types/bcryptjs": "^2.4.6",
+ "@types/jsonwebtoken": "^9.0.10",
+ "@types/multer": "^2.0.0",
+ "@types/node-forge": "^1.3.14",
+ "@types/swagger-jsdoc": "^6.0.4",
+ "@types/swagger-ui-express": "^4.1.8",
+ "archiver": "^7.0.1",
+ "bcryptjs": "^3.0.3",
+ "class-transformer": "^0.5.1",
+ "class-validator": "^0.14.0",
+ "cors": "^2.8.5",
+ "dotenv": "^16.0.3",
+ "express": "^4.18.2",
+ "helmet": "^6.0.1",
+ "jsonwebtoken": "^9.0.3",
+ "multer": "^2.0.2",
+ "node-forge": "^1.3.3",
+ "pg": "^8.10.0",
+ "reflect-metadata": "^0.1.13",
+ "selfsigned": "^5.4.0",
+ "sqlite3": "^5.1.7",
+ "swagger-jsdoc": "^6.2.8",
+ "swagger-ui-express": "^5.0.1",
+ "typeorm": "^0.3.12"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.13",
+ "@types/express": "^4.17.17",
+ "@types/node": "^18.15.11",
+ "ts-node": "^10.9.2",
+ "ts-node-dev": "^2.0.0",
+ "tsconfig-paths": "^4.2.0",
+ "typescript": "^5.0.0"
+ }
+}
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/revert-to-alias.ps1 b/Ark.Alliance.StartupCms.Ai.Backend/revert-to-alias.ps1
new file mode 100644
index 0000000000000000000000000000000000000000..56f6bfed5d24ccae6beee8261919709fe7c4ea55
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/revert-to-alias.ps1
@@ -0,0 +1,19 @@
+# Revert to using tsconfig path alias since relative paths don't work in Node.js
+# The path mapping in tsconfig.json already points @ark/portfolio-share to ../Ark.Portfolio.Share/index.ts
+
+Get-ChildItem -Path "src" -Recurse -Include *.ts | ForEach-Object {
+ $content = Get-Content $_.FullName -Raw
+
+ # Replace all relative Share imports back to the alias
+ $newContent = $content -replace "from '\.\./\.\./Ark\.Portfolio\.Share/index'", "from '@ark/portfolio-share'"
+ $newContent = $newContent -replace "from '\.\./\.\./\.\./Ark\.Portfolio\.Share/index'", "from '@ark/portfolio-share'"
+ $newContent = $newContent -replace "from '\.\./\.\./\.\./\.\./Ark\.Portfolio\.Share/enums/admin\.enums'", "from '@ark/portfolio-share'"
+
+ if ($newContent -ne $content) {
+ Set-Content -Path $_.FullName -Value $newContent -NoNewline
+ $relativePath = $_.FullName -replace [regex]::Escape("C:\Users\Criprtoswiss\source\repos\Ark.Portfolio\Ark.Portfolio.Backend\"), ""
+ Write-Host "Reverted: $relativePath"
+ }
+}
+
+Write-Host "All imports now use @ark/portfolio-share alias (tsconfig path mapping)"
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Armand.jfif b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Armand.jfif
new file mode 100644
index 0000000000000000000000000000000000000000..25c22ddaf415a736e6899871f7458de2c9359c22
Binary files /dev/null and b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Armand.jfif differ
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Bryan.jfif b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Bryan.jfif
new file mode 100644
index 0000000000000000000000000000000000000000..25d21585feb4c42bcd1dad6655c34abcff00cd64
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Bryan.jfif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b4c4a229f87235a174f89f547103440c9c10a9119b7293882d79bfc77d639e4b
+size 100388
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Lenny Avril.jpeg b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Lenny Avril.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..88f3fa9e01111f973ab8f20bc10a7bc9558928d3
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Lenny Avril.jpeg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4a8566d631ef4e43cf817d9cf4704d1d84cbde8ae820eaf21a18189be762525a
+size 127588
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Mario.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Mario.png
new file mode 100644
index 0000000000000000000000000000000000000000..21439f6d4ff46469b5b09f5e333288d9fc22bcb6
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/Mario.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b760e2d9907193ba96910cd3b7856e8862e739bb236bbf7b349cca94ce830210
+size 492061
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/RaduDinulescu.jfif b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/RaduDinulescu.jfif
new file mode 100644
index 0000000000000000000000000000000000000000..629faa011b88ea176c40f8632868bf1c277292e7
Binary files /dev/null and b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Profil_Avatars/RaduDinulescu.jfif differ
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.React.Component/components-hero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.React.Component/components-hero.png
new file mode 100644
index 0000000000000000000000000000000000000000..6095f22f5d09f6461c42e353af03364a53292100
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.React.Component/components-hero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:336b801f8ab538800e00f69180727b3ab5a8aba113f4f59b1808dbb7e7b5cd96
+size 4075992
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAiHero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAiHero.png
new file mode 100644
index 0000000000000000000000000000000000000000..4747cce51a26162d827db95c25b9baee45296233
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAiHero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:dc699238f96ac2a690579685416f3ee31564c5ad4d461309db73c5e11c3bb207
+size 384501
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAi_Hero.Png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAi_Hero.Png
new file mode 100644
index 0000000000000000000000000000000000000000..9596ab58d11c7823926ccfea3a9339e4dd627261
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAi_Hero.Png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ad36b3d343cb4fde6896ea5eef472bb0068f94abb1079ae561fc40923aece2cf
+size 1309535
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/Google_AI_Studio_2026-01-08T00_41_57.111Z.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/Google_AI_Studio_2026-01-08T00_41_57.111Z.png
new file mode 100644
index 0000000000000000000000000000000000000000..10d81472dde868f661e7b4541cd9854b8f96504b
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.StartupCms.AI/Google_AI_Studio_2026-01-08T00_41_57.111Z.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b5cd68e2a95d444d0016b6ae00830a4bfebe9b802aad2202cdaa150608117187
+size 1276740
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot10.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot10.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..545e15c4e95512074d58c91907db7d9c32986997
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot10.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9975e1830cb087bc177751ac162554ebe09ea1ee02dc881b0499954cc6fa13bc
+size 321808
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot11.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot11.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..2ec8207c17cd6559d1c86786ecd1e013a71d9142
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot11.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:39a5c84b9a23784f6ee68772b3292945d557d4681538e1bbe762a50fbaf49747
+size 378429
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot12.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot12.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..2ff7f228e3e9359e8a81847e0877c389b4acb3e0
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot12.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:459bb1c112c7a10eb22eb9c9a0d132c4badeaf78e23319e439c119bdc787f376
+size 155251
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot13.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot13.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..068b233c1fca51af8aaceef21e3a1862529f0c43
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot13.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:614315756f28c729ae556a3b284460a0d7f63e8e9e3f00f10d752f9dcd840127
+size 170264
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot14.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot14.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..0cf2808307669682bfced7468a04ef85b9ae622a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot14.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3ac92fa503174a5c4c6685c731a06b77dfe9aa7ff094f8ab3034d68fc8a0c0e1
+size 459307
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot2.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot2.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..75fc7e8910a064c50afad413ef8c27bcbf56ae99
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot2.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6c25f04b3a256ba08022b0a14e7f3fb8d4c8d5fdb68ab8e5e9390cee46dc753a
+size 465243
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot3.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot3.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..a5c10232d8c105d6396bc1d03f9a7cecc61dc804
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot3.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0b7e290bd1e3c51a836ab9ab613c594a1aa57315dc9a76f961899692e675ed3a
+size 397617
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot4.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot4.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..6c845c86ac723bbb1e00fc05a65f4c9ed3273a98
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot4.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f322678e0f5a499352eccd3a6a89e0190274fc19ab03ab08ed36c2d8e0731675
+size 213861
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot5.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot5.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..d05306ce7a2306af63c75d852f8deedf9544320f
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot5.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7a74f2a561083dc5041332b70f1ef267ebb3ba2b2fbf72767a84ff7b7e7dec4c
+size 215587
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot6.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot6.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..4207ff17a1c808bb56db7d3eb524d98fdd33738e
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot6.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:66435ea297e9f7466e72a3cd1f4671e1e4da1f914521786a3cdcd4987624aad6
+size 505004
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot7.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot7.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..fc843ea6466d799b3b000fdf29411bf71a00e75a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot7.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a2cea73cf7bf2a1e4dedadad32fc30e2b6720ed513cb0b3c2ee0679aaea46d5a
+size 369687
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot8.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot8.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..3d7c3f49fa5ae9495584308cf7b4eb1376640a9a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Bot8.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:4b554f447aa539e11f277200d0979cd6409c6f49bbb09968d043efce36b6ac12
+size 271418
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Capture.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Capture.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..fc843ea6466d799b3b000fdf29411bf71a00e75a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/Capture.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a2cea73cf7bf2a1e4dedadad32fc30e2b6720ed513cb0b3c2ee0679aaea46d5a
+size 369687
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot-hero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot-hero.png
new file mode 100644
index 0000000000000000000000000000000000000000..0f8c5ac5542ac129ee845d2e9b938c9925fefbc8
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot-hero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:57a8dd5a0928f512d557c043fa10d68c6b4106fda7dcf61b8a57f538c800d9b9
+size 1070123
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot1.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot1.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..d44cf89a01e264a1cdb87affc4ac800d3606fc40
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Bot/bot1.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:bcc256615a841b8686d03fa6159e33d37b1a40ccd0365288c946dd9740f0b2de
+size 258622
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/providers-hero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/providers-hero.png
new file mode 100644
index 0000000000000000000000000000000000000000..19506bfe8c45bb2595ab2708c0be1c7ab927b7d1
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/providers-hero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8fd701b06d1369df334415dddbe30c52070f5df207a025173ef8c65e7715f7c3
+size 1125206
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/trading-hero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/trading-hero.png
new file mode 100644
index 0000000000000000000000000000000000000000..3cf9cc1d696fb6da18376777e0cfcaa7c1f883b8
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/trading-hero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:83efb733710f1a58fba2767716bd3f17e6c795afd9cd1691adc6c7ef4d58aed7
+size 695430
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac9d932c48cb030163a11aceeb5e9b3fec12e204
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:19b5c66ce45f76dc2214f5e2cb9cebe7daaf44ca32ef8fb4d2d161b695833289
+size 4056660
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png.jpg b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ac9d932c48cb030163a11aceeb5e9b3fec12e204
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png.jpg
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:19b5c66ce45f76dc2214f5e2cb9cebe7daaf44ca32ef8fb4d2d161b695833289
+size 4056660
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_1.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..a4a551805bd97952063b9e984352f85bd1d119db
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_1.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f2e202213ddc181cdfcea31d207cdfc5697d0ac9f88415e7250a875f4f92aeb4
+size 2640749
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_Hero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_Hero.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a26be5f6ba257bf2f7c09eb630bf36459db81ca
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Alliance/Ark_Alliance_Hero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:119048c8b09932e7ba69e38073e74ff89cb2fe95021c8e6fd11708399322b352
+size 1181782
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Dashobard.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Dashobard.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..bfd362fe59d376c3280459cb1ddd3ac4e1c11456
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Dashobard.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b5f6573f8cf1d13dfca66b52329455f733935c65ddab4d567656e916ff39f738
+size 170191
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Hero_Carrousel.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Hero_Carrousel.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..be2323bd1b7e3f8868398a95a24d2ee2602043e0
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Hero_Carrousel.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:1fa16b5a96617ec4785fa1070ba68414b6e5e39c031044f774ec298f41d0b62c
+size 244080
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Projects.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Projects.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..99aa3c4d2e5c20ddaac48612147bdf259107e869
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_Projects.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c863dcb37da3cae3e73422ff0a23b80d59af76565922c52b1d1f5291aab5fbbd
+size 704598
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_ResumeManager.PNG b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_ResumeManager.PNG
new file mode 100644
index 0000000000000000000000000000000000000000..46d988f7247f458eb92c93d6ff3c3e189dad6495
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/Admin_ResumeManager.PNG
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:55c991692dc9d16b626e2021d9bf3154180ffc5ae18d6ca8e18905bf5b4113fb
+size 216510
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/portfolio-hero.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/portfolio-hero.png
new file mode 100644
index 0000000000000000000000000000000000000000..333e6a393cd893c0acef6a61b3148102c0c1a660
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Projects/Ark.Portfolio/portfolio-hero.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fc29d203e8ea95c84865d68f7762c5b23efa501678a8bec35c8bbcbf2bc212b6
+size 4157416
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Site/Icon.png b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Site/Icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..6174b39adc62e80e8d5a1dd409d3af3ba4aa4398
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/Assets/Site/Icon.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ac6bf4eb19783054f288a240b7a185984d3967f25d80ab59fb7e75d9dca2f631
+size 101421
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/config/database.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/config/database.ts
new file mode 100644
index 0000000000000000000000000000000000000000..74346da7097781fe3cb5fb274b087deab6bbf6b5
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/config/database.ts
@@ -0,0 +1,107 @@
+/**
+ * @fileoverview Database Configuration
+ * TypeORM DataSource configuration with support for SQLite and PostgreSQL.
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { DataSource } from 'typeorm';
+import dotenv from 'dotenv';
+import { Profile } from '../database/entities/profile.entity';
+import { Project } from '../database/entities/project.entity';
+import { ProjectTechnology } from '../database/entities/project-technology.entity';
+import { Education } from '../database/entities/education.entity';
+import { Experience } from '../database/entities/experience.entity';
+import { Skill } from '../database/entities/skill.entity';
+import { SkillCategory } from '../database/entities/skill-category.entity';
+import { Widget } from '../database/entities/widget.entity';
+import { Media } from '../database/entities/media.entity';
+import { ProjectPage } from '../database/entities/project-page.entity';
+import { ProjectFeature } from '../database/entities/project-feature.entity';
+import { ProjectController } from '../database/entities/project-controller.entity';
+import { ProjectEndpoint } from '../database/entities/project-endpoint.entity';
+import { TeamMember } from '../database/entities/team-member.entity';
+import { MenuItem } from '../database/entities/menu-item.entity';
+import { StyleConfig } from '../database/entities/style-config.entity';
+import { CarouselItem } from '../database/entities/carousel-item.entity';
+import { User } from '../database/entities/user.entity';
+import { UserRole } from '../database/entities/user-role.entity';
+import { RefreshToken } from '../database/entities/refresh-token.entity';
+import { AuditLog } from '../database/entities/audit-log.entity';
+import { AiSettings } from '../database/entities/ai-settings.entity';
+import { Outbox } from '../database/entities/outbox.entity';
+import { Technology } from '../database/entities/technology.entity';
+import { Language } from '../database/entities/language.entity';
+import { Hobby } from '../database/entities/hobby.entity';
+import { BusinessDomain } from '../database/entities/business-domain.entity';
+import { PageDefinition } from '../database/entities/page-definition.entity';
+import { Theme } from '../database/entities/theme.entity';
+import { Organization } from '../database/entities/organization.entity';
+import { Collaborator } from '../database/entities/collaborator.entity';
+import { Task } from '../database/entities/task.entity';
+import { PromptTemplate } from '../database/entities/prompt-template.entity';
+import { Page } from '../database/entities/page.entity';
+import { SeoMeta } from '../database/entities/seo-meta.entity';
+import { StructuredData } from '../database/entities/structured-data.entity';
+import { SiteSettings } from '../database/entities/site-settings.entity';
+
+dotenv.config();
+
+/** Database type from environment, defaults to SQLite */
+const dbType = (process.env.DB_TYPE || 'sqlite') as 'sqlite' | 'postgres';
+
+/**
+ * Base TypeORM configuration shared across database types.
+ */
+const baseConfig = {
+ synchronize: true,
+ logging: false,
+ entities: [
+ // User & Auth
+ User, UserRole, RefreshToken, AuditLog,
+ // Organization & Team
+ Organization, Collaborator, TeamMember, Task,
+ // Profile & Content
+ Profile, Project, ProjectTechnology, Technology, Education, Experience,
+ Skill, SkillCategory, Widget, Media, Language, Hobby, BusinessDomain,
+ // Project Details
+ ProjectPage, ProjectFeature, ProjectController, ProjectEndpoint,
+ // UI & Settings
+ MenuItem, StyleConfig, CarouselItem, PageDefinition, Theme,
+ // SEO & CMS
+ Page, SeoMeta, StructuredData, SiteSettings,
+ // System & AI
+ AiSettings, Outbox, PromptTemplate
+ ],
+ subscribers: [],
+ migrations: [],
+};
+
+/**
+ * PostgreSQL-specific configuration.
+ */
+const postgresConfig = {
+ type: 'postgres' as const,
+ host: process.env.DB_HOST || 'localhost',
+ port: parseInt(process.env.DB_PORT || '5432'),
+ username: process.env.DB_USER || 'postgres',
+ password: process.env.DB_PASSWORD || 'postgres',
+ database: process.env.DB_NAME || 'ark_portfolio',
+};
+
+/**
+ * SQLite-specific configuration.
+ */
+const sqliteConfig = {
+ type: 'sqlite' as const,
+ database: process.env.DB_KEY || './data/ark_portfolio.sqlite',
+};
+
+/**
+ * Application DataSource for TypeORM.
+ * @remarks Automatically selects SQLite or PostgreSQL based on DB_TYPE env variable.
+ */
+export const AppDataSource = new DataSource({
+ ...baseConfig,
+ ...(dbType === 'postgres' ? postgresConfig : sqliteConfig),
+});
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/config/swagger.config.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/config/swagger.config.ts
new file mode 100644
index 0000000000000000000000000000000000000000..897390cdb1d066cc2e7c4d9d6d98cf26661b60ae
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/config/swagger.config.ts
@@ -0,0 +1,195 @@
+import swaggerJsdoc from 'swagger-jsdoc';
+
+const options: swaggerJsdoc.Options = {
+ definition: {
+ openapi: '3.0.0',
+ info: {
+ title: 'Ark Portfolio API',
+ version: '1.0.0',
+ description: `
+## Ark.Alliance.StartupCms.Ai Backend API
+
+Complete REST API for the Ark.Alliance.StartupCms.Ai application.
+
+### API Groups:
+- **Public**: Profile, Projects, Resume, Carousel, Technologies
+- **Auth**: Login, Token Management
+- **Admin**: Full CRUD for all entities (requires JWT)
+
+### Authentication:
+Admin endpoints require JWT Bearer token. Use \`/api/auth/login\` to obtain a token.
+ `,
+ contact: {
+ name: 'Armand Richelet-Kleinberg',
+ email: 'arkleinberg@gmail.com'
+ },
+ license: {
+ name: 'MIT',
+ url: 'https://opensource.org/licenses/MIT'
+ }
+ },
+ servers: [
+ {
+ url: '/api',
+ description: 'Current Server (relative)'
+ },
+ {
+ url: 'http://localhost:3085/api',
+ description: 'Local Development (HTTP)'
+ },
+ {
+ url: 'https://localhost:3085/api',
+ description: 'Local Development (HTTPS)'
+ }
+ ],
+ tags: [
+ { name: 'Public - Profile', description: 'Portfolio owner profile information' },
+ { name: 'Public - Projects', description: 'Portfolio projects and presentations' },
+ { name: 'Public - Resume', description: 'CV/Resume data (experiences, skills, education)' },
+ { name: 'Public - Carousel', description: 'Homepage carousel items' },
+ { name: 'Public - Technologies', description: 'Technology catalog and metadata' },
+ { name: 'Public - Dashboard', description: 'Dashboard and widget data' },
+ { name: 'Auth', description: 'Authentication endpoints' },
+ { name: 'Admin - Projects', description: 'Project management (CRUD)' },
+ { name: 'Admin - Resume', description: 'Resume/CV management' },
+ { name: 'Admin - Media', description: 'Media asset management' },
+ { name: 'Admin - Carousel', description: 'Carousel item management' },
+ { name: 'Admin - Widgets', description: 'Widget configuration' },
+ { name: 'Admin - Menu', description: 'Navigation menu management' },
+ { name: 'Admin - Styles', description: 'Theme and style configuration' },
+ { name: 'Admin - AI', description: 'AI integration settings' }
+ ],
+ components: {
+ securitySchemes: {
+ bearerAuth: {
+ type: 'http',
+ scheme: 'bearer',
+ bearerFormat: 'JWT',
+ description: 'JWT token obtained from /api/auth/login'
+ }
+ },
+ schemas: {
+ Error: {
+ type: 'object',
+ properties: {
+ message: { type: 'string' },
+ error: { type: 'string' }
+ }
+ },
+ Profile: {
+ type: 'object',
+ properties: {
+ id: { type: 'integer' },
+ firstName: { type: 'string' },
+ lastName: { type: 'string' },
+ title: { type: 'string' },
+ overview: { type: 'string' },
+ email: { type: 'string' },
+ githubUrl: { type: 'string' },
+ linkedinUrl: { type: 'string' },
+ avatarUrl: { type: 'string' }
+ }
+ },
+ Project: {
+ type: 'object',
+ properties: {
+ id: { type: 'string' },
+ slug: { type: 'string' },
+ title: { type: 'string' },
+ subtitle: { type: 'string' },
+ description: { type: 'string' },
+ status: { type: 'string', enum: ['active', 'completed', 'archived'] },
+ isFeatured: { type: 'boolean' },
+ repositoryUrl: { type: 'string' },
+ demoUrl: { type: 'string' },
+ packageUrl: { type: 'string' }
+ }
+ },
+ CarouselItem: {
+ type: 'object',
+ properties: {
+ id: { type: 'integer' },
+ title: { type: 'string' },
+ subtitle: { type: 'string' },
+ imageUrl: { type: 'string' },
+ linkUrl: { type: 'string' },
+ order: { type: 'integer' }
+ }
+ },
+ Technology: {
+ type: 'object',
+ properties: {
+ id: { type: 'integer' },
+ key: { type: 'string' },
+ name: { type: 'string' },
+ label: { type: 'string' },
+ category: { type: 'string' },
+ description: { type: 'string' },
+ icon: { type: 'string' },
+ color: { type: 'string' },
+ website: { type: 'string' }
+ }
+ },
+ Experience: {
+ type: 'object',
+ properties: {
+ id: { type: 'integer' },
+ company: { type: 'string' },
+ position: { type: 'string' },
+ description: { type: 'string' },
+ startDate: { type: 'string', format: 'date' },
+ endDate: { type: 'string', format: 'date', nullable: true }
+ }
+ },
+ Skill: {
+ type: 'object',
+ properties: {
+ id: { type: 'integer' },
+ name: { type: 'string' },
+ level: { type: 'string' },
+ categoryId: { type: 'integer' }
+ }
+ },
+ Education: {
+ type: 'object',
+ properties: {
+ id: { type: 'integer' },
+ institution: { type: 'string' },
+ degree: { type: 'string' },
+ fieldOfStudy: { type: 'string' },
+ startDate: { type: 'string', format: 'date' },
+ endDate: { type: 'string', format: 'date' }
+ }
+ },
+ LoginRequest: {
+ type: 'object',
+ required: ['username', 'password'],
+ properties: {
+ username: { type: 'string' },
+ password: { type: 'string' }
+ }
+ },
+ LoginResponse: {
+ type: 'object',
+ properties: {
+ token: { type: 'string' },
+ user: {
+ type: 'object',
+ properties: {
+ id: { type: 'integer' },
+ username: { type: 'string' }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ apis: [
+ './src/routes/*.ts',
+ './src/controllers/*.ts'
+ ]
+};
+
+export const swaggerSpec = swaggerJsdoc(options);
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/admin.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/admin.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d4fb14deaa783e232726c12c4ebc47d3e64f028f
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/admin.controller.ts
@@ -0,0 +1,682 @@
+/**
+ * @fileoverview Admin Controller
+ * Handles all administrative API endpoints.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { AdminProjectService } from '../services/admin-project.service';
+import { AdminResumeService } from '../services/admin-resume.service';
+import { AdminWidgetService } from '../services/admin-widget.service';
+import { AdminMenuService } from '../services/admin-menu.service';
+import { AdminStyleService } from '../services/admin-style.service';
+import { AdminMediaService } from '../services/admin-media.service';
+import { AdminCarouselService } from '../services/admin-carousel.service';
+import { AdminThemeService, AdminThemeDto } from '../services/admin-theme.service';
+import { ThemeAiService, ThemeAiRequest } from '../services/theme-ai.service';
+import { AiService } from '../services/ai.service';
+import {
+ AdminProjectDto, AdminResumeDto, AdminWidgetDto, AdminMenuItemDto,
+ AdminStyleConfigDto, UploadMediaDto, ReorderWidgetsDto, ReorderMenuItemsDto,
+ AdminCarouselItemDto, ReorderCarouselDto, AdminExperienceDto, AdminEducationDto,
+ AdminSkillDto, SkillCategoryDto, ReorderSkillsDto, AiSettingsDto,
+ LanguageDto, HobbyDto, BusinessDomainDto
+} from '@arkalliance/startupcms-ai-share';
+
+export class AdminController extends BaseController {
+ private projectService: AdminProjectService;
+ private resumeService: AdminResumeService;
+ private widgetService: AdminWidgetService;
+ private menuService: AdminMenuService;
+ private styleService: AdminStyleService;
+ private mediaService: AdminMediaService;
+ private carouselService: AdminCarouselService;
+ private themeService: AdminThemeService;
+ private themeAiService: ThemeAiService;
+ private aiService: AiService;
+
+ constructor() {
+ super();
+ this.projectService = new AdminProjectService();
+ this.resumeService = new AdminResumeService();
+ this.widgetService = new AdminWidgetService();
+ this.menuService = new AdminMenuService();
+ this.styleService = new AdminStyleService();
+ this.mediaService = new AdminMediaService();
+ this.carouselService = new AdminCarouselService();
+ this.themeService = new AdminThemeService();
+ this.themeAiService = new ThemeAiService();
+ this.aiService = new AiService();
+ }
+
+ // ============================================
+ // Project Endpoints
+ // ============================================
+
+ async getProjects(req: Request, res: Response) {
+ const page = parseInt(req.query.page as string) || 1;
+ const pageSize = parseInt(req.query.pageSize as string) || 10;
+ const search = req.query.search as string;
+ const result = await this.projectService.getAllProjects(page, pageSize, search);
+ return this.ok(res, result);
+ }
+
+ async getProject(req: Request, res: Response) {
+ const result = await this.projectService.getProjectById(req.params.id);
+ if (!result) return this.notFound(res, 'Project not found');
+ return this.ok(res, result);
+ }
+
+ async createProject(req: Request, res: Response) {
+ const dto = req.body as AdminProjectDto;
+ const result = await this.projectService.createProject(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateProject(req: Request, res: Response) {
+ const dto = req.body as AdminProjectDto;
+ const result = await this.projectService.updateProject(req.params.id, dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteProject(req: Request, res: Response) {
+ const result = await this.projectService.deleteProject(req.params.id);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // RESUME Endpoints
+ // ============================================
+
+ async getResume(req: Request, res: Response) {
+ const result = await this.resumeService.getFullResume();
+ return this.ok(res, result);
+ }
+
+ async updateProfile(req: Request, res: Response) {
+ const dto = req.body as AdminResumeDto['profile'];
+ const result = await this.resumeService.updateProfile(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // Experience CRUD
+ async createExperience(req: Request, res: Response) {
+ const dto = req.body as AdminExperienceDto;
+ const result = await this.resumeService.createExperience(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateExperience(req: Request, res: Response) {
+ const dto = req.body as AdminExperienceDto;
+ const result = await this.resumeService.updateExperience(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteExperience(req: Request, res: Response) {
+ const result = await this.resumeService.deleteExperience(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // Education CRUD
+ async createEducation(req: Request, res: Response) {
+ const dto = req.body as AdminEducationDto;
+ const result = await this.resumeService.createEducation(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateEducation(req: Request, res: Response) {
+ const dto = req.body as AdminEducationDto;
+ const result = await this.resumeService.updateEducation(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteEducation(req: Request, res: Response) {
+ const result = await this.resumeService.deleteEducation(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderExperiences(req: Request, res: Response) {
+ const { experienceIds } = req.body as { experienceIds: number[] };
+ const result = await this.resumeService.reorderExperiences(experienceIds);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderEducation(req: Request, res: Response) {
+ const { educationIds } = req.body as { educationIds: number[] };
+ const result = await this.resumeService.reorderEducation(educationIds);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // Skills CRUD
+ async createSkill(req: Request, res: Response) {
+ const dto = req.body as AdminSkillDto;
+ const result = await this.resumeService.createSkill(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateSkill(req: Request, res: Response) {
+ const dto = req.body as AdminSkillDto;
+ const result = await this.resumeService.updateSkill(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteSkill(req: Request, res: Response) {
+ const result = await this.resumeService.deleteSkill(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderSkills(req: Request, res: Response) {
+ const dto = req.body as ReorderSkillsDto;
+ const result = await this.resumeService.reorderSkills(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // Skill Categories CRUD
+ async getSkillCategories(req: Request, res: Response) {
+ const result = await this.resumeService.getSkillCategories();
+ return this.ok(res, result);
+ }
+
+ async createSkillCategory(req: Request, res: Response) {
+ const dto = req.body as SkillCategoryDto;
+ const result = await this.resumeService.createSkillCategory(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateSkillCategory(req: Request, res: Response) {
+ const dto = req.body as SkillCategoryDto;
+ const result = await this.resumeService.updateSkillCategory(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteSkillCategory(req: Request, res: Response) {
+ const result = await this.resumeService.deleteSkillCategory(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Language Endpoints
+ // ============================================
+
+ async createLanguage(req: Request, res: Response) {
+ const dto = req.body as LanguageDto;
+ const result = await this.resumeService.createLanguage(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateLanguage(req: Request, res: Response) {
+ const dto = req.body as LanguageDto;
+ const result = await this.resumeService.updateLanguage(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteLanguage(req: Request, res: Response) {
+ const result = await this.resumeService.deleteLanguage(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderLanguages(req: Request, res: Response) {
+ const { languageIds } = req.body as { languageIds: number[] };
+ const result = await this.resumeService.reorderLanguages(languageIds);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Hobby Endpoints
+ // ============================================
+
+ async createHobby(req: Request, res: Response) {
+ const dto = req.body as HobbyDto;
+ const result = await this.resumeService.createHobby(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateHobby(req: Request, res: Response) {
+ const dto = req.body as HobbyDto;
+ const result = await this.resumeService.updateHobby(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteHobby(req: Request, res: Response) {
+ const result = await this.resumeService.deleteHobby(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderHobbies(req: Request, res: Response) {
+ const { hobbyIds } = req.body as { hobbyIds: number[] };
+ const result = await this.resumeService.reorderHobbies(hobbyIds);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Business Domain Endpoints
+ // ============================================
+
+ async createBusinessDomain(req: Request, res: Response) {
+ const dto = req.body as BusinessDomainDto;
+ const result = await this.resumeService.createBusinessDomain(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateBusinessDomain(req: Request, res: Response) {
+ const dto = req.body as BusinessDomainDto;
+ const result = await this.resumeService.updateBusinessDomain(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteBusinessDomain(req: Request, res: Response) {
+ const result = await this.resumeService.deleteBusinessDomain(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderBusinessDomains(req: Request, res: Response) {
+ const { domainIds } = req.body as { domainIds: number[] };
+ const result = await this.resumeService.reorderBusinessDomains(domainIds);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // AI Endpoints
+ // ============================================
+
+ async getAiSettings(req: Request, res: Response) {
+ const result = await this.aiService.getSettings();
+ return this.ok(res, result);
+ }
+
+ async updateAiSettings(req: Request, res: Response) {
+ const dto = req.body as AiSettingsDto;
+ const result = await this.aiService.updateSettings(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async testAiConnection(req: Request, res: Response) {
+ const result = await this.aiService.testConnection();
+ return this.ok(res, result);
+ }
+
+ async getAiProviderModels(req: Request, res: Response) {
+ const provider = req.params.provider;
+ const models = await this.aiService.getProviderModels(provider);
+ return this.ok(res, models);
+ }
+
+ async organizeSkillsWithAi(req: Request, res: Response) {
+ const skills = req.body.skills;
+ const result = await this.aiService.organizeSkills(skills);
+ return this.ok(res, result);
+ }
+
+ async improveTextWithAi(req: Request, res: Response) {
+ const { text, context } = req.body;
+ const result = await this.aiService.improveDescription(text, context);
+ return this.ok(res, { result });
+ }
+
+ // ============================================
+ // Widget Endpoints
+ // ============================================
+
+ async getWidgets(req: Request, res: Response) {
+ const pageId = req.query.pageId as string;
+ const result = await this.widgetService.getWidgets(pageId);
+ return this.ok(res, result);
+ }
+
+ async createWidget(req: Request, res: Response) {
+ const dto = req.body as AdminWidgetDto;
+ const result = await this.widgetService.createWidget(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateWidget(req: Request, res: Response) {
+ const dto = req.body as AdminWidgetDto;
+ const result = await this.widgetService.updateWidget(req.params.id, dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteWidget(req: Request, res: Response) {
+ const result = await this.widgetService.deleteWidget(req.params.id);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderWidgets(req: Request, res: Response) {
+ const dto = req.body as ReorderWidgetsDto;
+ const result = await this.widgetService.reorderWidgets(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Menu Endpoints
+ // ============================================
+
+ async getMenu(req: Request, res: Response) {
+ const position = req.query.position as any;
+ const result = await this.menuService.getMenuByPosition(position);
+ return this.ok(res, result);
+ }
+
+ async createMenuItem(req: Request, res: Response) {
+ const dto = req.body as AdminMenuItemDto;
+ const result = await this.menuService.createMenuItem(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateMenuItem(req: Request, res: Response) {
+ const dto = req.body as AdminMenuItemDto;
+ const result = await this.menuService.updateMenuItem(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteMenuItem(req: Request, res: Response) {
+ const result = await this.menuService.deleteMenuItem(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderMenu(req: Request, res: Response) {
+ const dto = req.body as ReorderMenuItemsDto;
+ const result = await this.menuService.reorderMenuItems(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Style Endpoints
+ // ============================================
+
+ async getStyles(req: Request, res: Response) {
+ const result = await this.styleService.getAllStyles();
+ return this.ok(res, result);
+ }
+
+ async getActiveStyle(req: Request, res: Response) {
+ const result = await this.styleService.getActiveStyle();
+ return this.ok(res, result);
+ }
+
+ async createStyle(req: Request, res: Response) {
+ const dto = req.body as AdminStyleConfigDto;
+ const result = await this.styleService.createStyle(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateStyle(req: Request, res: Response) {
+ const dto = req.body as AdminStyleConfigDto;
+ const result = await this.styleService.updateStyle(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteStyle(req: Request, res: Response) {
+ const result = await this.styleService.deleteStyle(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async activateStyle(req: Request, res: Response) {
+ const result = await this.styleService.activateStyle(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Media Endpoints
+ // ============================================
+
+ /**
+ * Get all media with optional filtering.
+ * @param req - Express request with query params (type, search, tags, page, pageSize)
+ * @param res - Express response
+ */
+ async getMedia(req: Request, res: Response) {
+ const params = {
+ type: req.query.type as any,
+ search: req.query.search as string,
+ tags: req.query.tags ? (req.query.tags as string).split(',') : undefined,
+ page: parseInt(req.query.page as string) || 1,
+ pageSize: parseInt(req.query.pageSize as string) || 50
+ };
+ const result = await this.mediaService.getAllMedia(params);
+ return this.ok(res, result);
+ }
+
+ /**
+ * Get media by unique key.
+ * @param req - Express request with key param
+ * @param res - Express response
+ */
+ async getMediaByKey(req: Request, res: Response) {
+ const result = await this.mediaService.getByKey(req.params.key);
+ if (!result) return this.notFound(res, 'Media not found');
+ return this.ok(res, result);
+ }
+
+ /**
+ * Get all available tags.
+ * @param req - Express request
+ * @param res - Express response
+ */
+ async getMediaTags(req: Request, res: Response) {
+ const result = await this.mediaService.getAllTags();
+ return this.ok(res, result);
+ }
+
+ /**
+ * Upload a new media file.
+ * @param req - Express request with file and body data
+ * @param res - Express response
+ */
+ async uploadMedia(req: Request, res: Response) {
+ if (!req.file) {
+ return this.fail(res, new Error('No file uploaded'));
+ }
+ const data = {
+ name: req.body.name || req.file.originalname,
+ key: req.body.key,
+ altText: req.body.altText,
+ description: req.body.description,
+ tags: req.body.tags ? JSON.parse(req.body.tags) : [],
+ metadata: req.body.metadata ? JSON.parse(req.body.metadata) : undefined,
+ isPublic: req.body.isPublic !== 'false'
+ };
+ const result = await this.mediaService.createFromUpload(req.file, data);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ /**
+ * Create media from external URL.
+ * @param req - Express request with URL and metadata
+ * @param res - Express response
+ */
+ async createMediaFromUrl(req: Request, res: Response) {
+ const { url, type, name, key, altText, description, tags, metadata } = req.body;
+ if (!url || !type || !name) {
+ return this.fail(res, new Error('url, type, and name are required'));
+ }
+ const result = await this.mediaService.createFromUrl(url, type, {
+ name, key, altText, description, tags, metadata
+ });
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ /**
+ * Update media metadata.
+ * @param req - Express request with id param and body data
+ * @param res - Express response
+ */
+ async updateMedia(req: Request, res: Response) {
+ const { name, key, altText, description, tags, metadata, isPublic } = req.body;
+ const result = await this.mediaService.updateMedia(req.params.id, {
+ name, key, altText, description, tags, metadata, isPublic
+ });
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ /**
+ * Delete media by ID.
+ * @param req - Express request with id param
+ * @param res - Express response
+ */
+ async deleteMedia(req: Request, res: Response) {
+ const result = await this.mediaService.deleteMedia(req.params.id);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Carousel Endpoints
+ // ============================================
+
+ async getCarousel(req: Request, res: Response) {
+ const result = await this.carouselService.getAllCarouselItems();
+ return this.ok(res, result);
+ }
+
+ async createCarouselItem(req: Request, res: Response) {
+ const dto = req.body as AdminCarouselItemDto;
+ const result = await this.carouselService.createCarouselItem(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateCarouselItem(req: Request, res: Response) {
+ const dto = req.body as AdminCarouselItemDto;
+ const result = await this.carouselService.updateCarouselItem(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteCarouselItem(req: Request, res: Response) {
+ const result = await this.carouselService.deleteCarouselItem(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderCarousel(req: Request, res: Response) {
+ const dto = req.body as ReorderCarouselDto;
+ const result = await this.carouselService.reorderCarouselItems(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Theme Management Endpoints
+ // ============================================
+
+ async getThemes(req: Request, res: Response) {
+ const result = await this.themeService.getAllThemes();
+ return this.ok(res, result);
+ }
+
+ async getTheme(req: Request, res: Response) {
+ const result = await this.themeService.getThemeById(parseInt(req.params.id));
+ if (!result) return this.notFound(res, 'Theme not found');
+ return this.ok(res, result);
+ }
+
+ async createTheme(req: Request, res: Response) {
+ const dto = req.body as AdminThemeDto;
+ const result = await this.themeService.createTheme(dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async updateTheme(req: Request, res: Response) {
+ const dto = req.body as AdminThemeDto;
+ const result = await this.themeService.updateTheme(parseInt(req.params.id), dto);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async deleteTheme(req: Request, res: Response) {
+ const result = await this.themeService.deleteTheme(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async setDefaultTheme(req: Request, res: Response) {
+ const result = await this.themeService.setDefaultTheme(parseInt(req.params.id));
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ async reorderThemes(req: Request, res: Response) {
+ const { themeIds } = req.body as { themeIds: number[] };
+ const result = await this.themeService.reorderThemes(themeIds);
+ if (!result.success) return this.fail(res, new Error(result.message));
+ return this.ok(res, result);
+ }
+
+ // ============================================
+ // Theme AI Endpoints
+ // ============================================
+
+ async themeAiChat(req: Request, res: Response) {
+ const request = req.body as ThemeAiRequest;
+ const result = await this.themeAiService.chat(request);
+ if (result.error) return this.fail(res, new Error(result.error));
+ return this.ok(res, result);
+ }
+
+ async themeAiGenerate(req: Request, res: Response) {
+ const { description } = req.body as { description: string };
+ const result = await this.themeAiService.generateTheme(description);
+ if (result.error) return this.fail(res, new Error(result.error));
+ return this.ok(res, result);
+ }
+
+ async themeAiSuggest(req: Request, res: Response) {
+ const { css, goal } = req.body as { css: string; goal?: string };
+ const result = await this.themeAiService.suggestImprovements(css, goal);
+ if (result.error) return this.fail(res, new Error(result.error));
+ return this.ok(res, result);
+ }
+}
+
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/ai-profile.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/ai-profile.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e7092f32c353e55cf24b5675f1c4bca8a7338839
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/ai-profile.controller.ts
@@ -0,0 +1,188 @@
+/**
+ * @fileoverview AI Profile Controller
+ * API endpoints for AI-assisted profile generation and prompt template management.
+ *
+ * @module controllers/ai-profile
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { aiProfileService, AiProfileInput } from '../services/ai-profile.service';
+import { promptTemplateService } from '../services/prompt-template.service';
+
+/**
+ * Controller for AI profile generation endpoints.
+ *
+ * @class AiProfileController
+ * @extends BaseController
+ */
+export class AiProfileController extends BaseController {
+ /**
+ * Generate a profile using AI from description.
+ *
+ * @route POST /api/ai/generate-profile
+ * @access Admin
+ *
+ * @param req - Express request with profile input
+ * @param res - Express response
+ * @returns Generated profile result
+ *
+ * @example
+ * // Request body
+ * {
+ * "firstName": "John",
+ * "lastName": "Doe",
+ * "function": "Software Engineer",
+ * "managerName": "Armand Richelet-Kleinberg",
+ * "description": "Experienced developer with...",
+ * "urls": "https://linkedin.com/in/johndoe",
+ * "avatarBase64": "data:image/jpeg;base64,..."
+ * }
+ */
+ generateProfile = async (req: Request, res: Response) => {
+ try {
+ const input: AiProfileInput = {
+ firstName: req.body.firstName,
+ lastName: req.body.lastName,
+ function: req.body.function,
+ managerName: req.body.managerName,
+ description: req.body.description,
+ urls: req.body.urls,
+ avatarBase64: req.body.avatarBase64,
+ userId: req.body.userId,
+ promptName: req.body.promptName
+ };
+
+ // Validate required fields
+ if (!input.firstName || !input.lastName) {
+ return this.fail(res, new Error('firstName and lastName are required'));
+ }
+ if (!input.function) {
+ return this.fail(res, new Error('function (job title) is required'));
+ }
+ if (!input.description) {
+ return this.fail(res, new Error('description is required'));
+ }
+
+ const result = await aiProfileService.generateProfile(input);
+
+ if (result.success) {
+ return this.ok(res, result);
+ } else {
+ return this.fail(res, new Error(result.message));
+ }
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ };
+
+ /**
+ * Get all prompt templates.
+ *
+ * @route GET /api/ai/prompts
+ * @access Admin
+ */
+ getPromptTemplates = async (req: Request, res: Response) => {
+ try {
+ const templates = await promptTemplateService.getAll();
+ return this.ok(res, templates);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ };
+
+ /**
+ * Get a prompt template by name.
+ *
+ * @route GET /api/ai/prompts/:name
+ * @access Admin
+ */
+ getPromptByName = async (req: Request, res: Response) => {
+ try {
+ const { name } = req.params;
+ const template = await promptTemplateService.getByName(name);
+
+ if (!template) {
+ return this.notFound(res, 'Prompt template not found');
+ }
+
+ return this.ok(res, template);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ };
+
+ /**
+ * Create a new prompt template.
+ *
+ * @route POST /api/ai/prompts
+ * @access Admin
+ */
+ createPromptTemplate = async (req: Request, res: Response) => {
+ try {
+ const { name, description, systemPrompt, clientPromptTemplate, outputFormat } = req.body;
+
+ if (!name || !systemPrompt || !clientPromptTemplate) {
+ return this.fail(res, new Error('name, systemPrompt, and clientPromptTemplate are required'));
+ }
+
+ const template = await promptTemplateService.create({
+ name,
+ description,
+ systemPrompt,
+ clientPromptTemplate,
+ outputFormat
+ });
+
+ return res.status(201).json(template);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ };
+
+ /**
+ * Update a prompt template.
+ *
+ * @route PUT /api/ai/prompts/:id
+ * @access Admin
+ */
+ updatePromptTemplate = async (req: Request, res: Response) => {
+ try {
+ const id = parseInt(req.params.id);
+ const template = await promptTemplateService.update(id, req.body);
+
+ if (!template) {
+ return this.notFound(res, 'Prompt template not found');
+ }
+
+ return this.ok(res, template);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ };
+
+ /**
+ * Delete a prompt template.
+ *
+ * @route DELETE /api/ai/prompts/:id
+ * @access Admin
+ */
+ deletePromptTemplate = async (req: Request, res: Response) => {
+ try {
+ const id = parseInt(req.params.id);
+ const success = await promptTemplateService.delete(id);
+
+ if (!success) {
+ return this.notFound(res, 'Prompt template not found');
+ }
+
+ return this.ok(res, { message: 'Prompt template deleted' });
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ };
+}
+
+// Singleton instance
+export const aiProfileController = new AiProfileController();
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/audit-log.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/audit-log.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9384b31cdc6f695d6c8a92b8b8fc9603f9a2b166
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/audit-log.controller.ts
@@ -0,0 +1,85 @@
+/**
+ * @fileoverview Audit Log Controller
+ * API endpoints for viewing audit logs.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { AuditLogService } from '../services/audit-log.service';
+import { AuthenticatedRequest } from '../middleware/auth.middleware';
+import { AuditLogQueryDto } from '@arkalliance/startupcms-ai-share';
+
+/**
+ * Controller for audit log endpoints.
+ */
+export class AuditLogController extends BaseController {
+ private auditLogService: AuditLogService;
+
+ constructor() {
+ super();
+ this.auditLogService = new AuditLogService();
+ }
+
+ /**
+ * GET /api/admin/audit-logs
+ * Query audit logs with filters (supervisor+ only).
+ */
+ async query(req: AuthenticatedRequest, res: Response) {
+ try {
+ const query: AuditLogQueryDto = {
+ userId: req.query.userId as string,
+ actions: req.query.actions ? (req.query.actions as string).split(',') as any : undefined,
+ startDate: req.query.startDate as string,
+ endDate: req.query.endDate as string,
+ success: req.query.success !== undefined ? req.query.success === 'true' : undefined,
+ ipAddress: req.query.ipAddress as string,
+ page: req.query.page ? parseInt(req.query.page as string) : 1,
+ limit: req.query.limit ? parseInt(req.query.limit as string) : 50
+ };
+
+ const result = await this.auditLogService.query(query);
+ return this.ok(res, result);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/admin/audit-logs/user/:userId
+ * Get login history for a specific user (supervisor+ only).
+ */
+ async getUserLoginHistory(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { userId } = req.params;
+ const limit = req.query.limit ? parseInt(req.query.limit as string) : 10;
+
+ const history = await this.auditLogService.getLoginHistory(userId, limit);
+ return this.ok(res, history);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/admin/audit-logs/my-history
+ * Get current user's own login history.
+ */
+ async getMyLoginHistory(req: AuthenticatedRequest, res: Response) {
+ try {
+ const userId = req.user?.id;
+ if (!userId) {
+ return this.unauthorized(res, 'Not authenticated');
+ }
+
+ const limit = req.query.limit ? parseInt(req.query.limit as string) : 10;
+ const history = await this.auditLogService.getLoginHistory(userId, limit);
+ return this.ok(res, history);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/auth.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/auth.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..92027ec951de4557341ca1c4b22fa35daac09676
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/auth.controller.ts
@@ -0,0 +1,64 @@
+import { Request, Response, NextFunction } from 'express';
+import { BaseController } from './base.controller';
+import { AuthService } from '../services/auth.service';
+
+export class AuthController extends BaseController {
+ private authService: AuthService;
+
+ constructor() {
+ super();
+ this.authService = new AuthService();
+ }
+
+ async login(req: Request, res: Response) {
+ const { username, password } = req.body;
+
+ if (!username || !password) {
+ return this.clientError(res, 'Username and password are required');
+ }
+
+ const result = await this.authService.login(username, password);
+
+ if (!result) {
+ return this.unauthorized(res, 'Invalid credentials');
+ }
+
+ return this.ok(res, result);
+ }
+
+ async getMe(req: Request, res: Response) {
+ // The user is attached to the request by the auth middleware
+ const user = (req as any).user;
+ if (!user) {
+ return this.unauthorized(res, 'Not authenticated');
+ }
+ return this.ok(res, {
+ id: user.id,
+ username: user.username,
+ role: user.role
+ });
+ }
+
+ async changePassword(req: Request, res: Response) {
+ const user = (req as any).user;
+ if (!user) {
+ return this.unauthorized(res, 'Not authenticated');
+ }
+
+ const { oldPassword, newPassword } = req.body;
+ if (!oldPassword || !newPassword) {
+ return this.clientError(res, 'Old password and new password are required');
+ }
+
+ try {
+ const success = await this.authService.changePassword(user.id, oldPassword, newPassword);
+ if (!success) {
+ return this.clientError(res, 'Invalid old password');
+ }
+ return this.ok(res, { message: 'Password changed successfully' });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/base.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/base.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a13bd713380c0de7904c0c9c5cc0aae0be55f7a3
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/base.controller.ts
@@ -0,0 +1,97 @@
+/**
+ * @fileoverview Base Controller
+ * Provides common HTTP response helper methods for all API controllers.
+ * Implements a consistent response format across the application.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Response } from 'express';
+
+/**
+ * Abstract base controller with standardized HTTP response methods.
+ * All API controllers should extend this class to ensure consistent
+ * error handling and response formatting.
+ *
+ * @example
+ * ```typescript
+ * class MyController extends BaseController {
+ * async getResource(req: Request, res: Response) {
+ * const data = await service.getData();
+ * return data ? this.ok(res, data) : this.notFound(res);
+ * }
+ * }
+ * ```
+ */
+export abstract class BaseController {
+ /**
+ * Sends a 200 OK response with optional data payload.
+ * @param res - Express response object
+ * @param dto - Optional data to include in response body
+ */
+ protected ok(res: Response, dto?: T) {
+ if (!!dto) {
+ return res.status(200).json(dto);
+ } else {
+ return res.sendStatus(200);
+ }
+ }
+
+ /**
+ * Sends a 201 Created response.
+ * @param res - Express response object
+ */
+ protected created(res: Response) {
+ return res.sendStatus(201);
+ }
+
+ /**
+ * Sends a 400 Bad Request response.
+ * @param res - Express response object
+ * @param message - Optional error message (defaults to 'Bad Request')
+ */
+ protected clientError(res: Response, message?: string) {
+ return res.status(400).json({ message: message ? message : 'Bad Request' });
+ }
+
+ /**
+ * Sends a 401 Unauthorized response.
+ * @param res - Express response object
+ * @param message - Optional error message (defaults to 'Unauthorized')
+ */
+ protected unauthorized(res: Response, message?: string) {
+ return res.status(401).json({ message: message ? message : 'Unauthorized' });
+ }
+
+ /**
+ * Sends a 403 Forbidden response.
+ * @param res - Express response object
+ * @param message - Optional error message (defaults to 'Forbidden')
+ */
+ protected forbidden(res: Response, message?: string) {
+ return res.status(403).json({ message: message ? message : 'Forbidden' });
+ }
+
+ /**
+ * Sends a 404 Not Found response.
+ * @param res - Express response object
+ * @param message - Optional error message (defaults to 'Not Found')
+ */
+ protected notFound(res: Response, message?: string) {
+ return res.status(404).json({ message: message ? message : 'Not Found' });
+ }
+
+ /**
+ * Sends a 500 Internal Server Error response.
+ * Logs the error to console for debugging.
+ * @param res - Express response object
+ * @param error - Error object or message string
+ */
+ protected fail(res: Response, error: Error | string) {
+ console.error(error);
+ return res.status(500).json({
+ message: error.toString()
+ });
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/carousel.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/carousel.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e00cd8e6e0a8c3538a91bd7216dc744379078f87
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/carousel.controller.ts
@@ -0,0 +1,56 @@
+/**
+ * @fileoverview Carousel Controller
+ * Public endpoint for carousel data on homepage.
+ *
+ * @author Ark.Alliance
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { AdminCarouselService } from '../services/admin-carousel.service';
+import { CarouselSlideDto } from '@arkalliance/startupcms-ai-share';
+
+/**
+ * Public Carousel Controller
+ *
+ * Provides public (unauthenticated) access to carousel data for homepage.
+ * Uses the same data source as admin but only returns active, public-safe fields.
+ */
+export class CarouselController extends BaseController {
+ private carouselService: AdminCarouselService;
+
+ constructor() {
+ super();
+ this.carouselService = new AdminCarouselService();
+ }
+
+ /**
+ * Get all active carousel items for public display.
+ * Maps admin carousel items to public CarouselSlideDto.
+ *
+ * @param req - Express request
+ * @param res - Express response
+ * @returns Array of CarouselSlideDto
+ */
+ async getCarousel(req: Request, res: Response) {
+ const items = await this.carouselService.getAllCarouselItems();
+
+ // Filter only active items and map to public DTO
+ const slides: CarouselSlideDto[] = items
+ .filter((item: any) => item.isActive)
+ .sort((a: any, b: any) => a.order - b.order)
+ .map((item: any) => ({
+ id: item.id,
+ title: item.title,
+ subtitle: item.subtitle,
+ description: item.description,
+ imageUrl: item.imageUrl,
+ ctaLabel: item.linkText || 'Learn More',
+ ctaLink: item.linkUrl || (item.projectId ? `/projects/${item.projectId}` : '/projects'),
+ }));
+
+ return this.ok(res, slides);
+ }
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/collaborator.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/collaborator.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9dfab87490317cf228608c938d6d6bb4ee672e5b
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/collaborator.controller.ts
@@ -0,0 +1,135 @@
+/**
+ * @fileoverview Collaborator Controller
+ * API endpoints for team member management.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { CollaboratorService } from '../services/collaborator.service';
+import { AuthenticatedRequest } from '../middleware/auth.middleware';
+
+/**
+ * Controller for collaborator/team endpoints.
+ */
+export class CollaboratorController extends BaseController {
+ private collaboratorService: CollaboratorService;
+
+ constructor() {
+ super();
+ this.collaboratorService = new CollaboratorService();
+ }
+
+ /**
+ * GET /api/team
+ * Get organization chart (public).
+ * If organizationId is not provided, uses the default (first) organization.
+ */
+ async getOrgChart(req: Request, res: Response) {
+ try {
+ let organizationId = req.query.organizationId as string | undefined;
+
+ // If no organizationId provided, get the default organization
+ if (!organizationId) {
+ const defaultOrg = await this.collaboratorService.getDefaultOrganization();
+ if (!defaultOrg) {
+ return this.notFound(res, 'No organization found');
+ }
+ organizationId = defaultOrg.id;
+ }
+
+ const orgChart = await this.collaboratorService.getOrgChart(organizationId);
+ if (!orgChart) {
+ return this.notFound(res, 'Organization not found');
+ }
+ return this.ok(res, orgChart);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/team/:id
+ * Get collaborator details (public).
+ */
+ async getById(req: Request, res: Response) {
+ try {
+ const { id } = req.params;
+ const collaborator = await this.collaboratorService.getWithReports(id);
+ if (!collaborator) {
+ return this.notFound(res, 'Collaborator not found');
+ }
+ return this.ok(res, collaborator);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/admin/collaborators
+ * List all collaborators (supervisor+ only).
+ */
+ async list(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { organizationId } = req.query;
+ if (!organizationId || typeof organizationId !== 'string') {
+ return this.clientError(res, 'organizationId query parameter is required');
+ }
+
+ const collaborators = await this.collaboratorService.getByOrganization(organizationId);
+ return this.ok(res, collaborators);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * POST /api/admin/collaborators
+ * Create a new collaborator (supervisor+ only).
+ */
+ async create(req: AuthenticatedRequest, res: Response) {
+ try {
+ const collaborator = await this.collaboratorService.create(req.body);
+ return this.ok(res, collaborator);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * PUT /api/admin/collaborators/:id
+ * Update a collaborator (supervisor+ only).
+ */
+ async update(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const collaborator = await this.collaboratorService.update(id, req.body);
+ if (!collaborator) {
+ return this.notFound(res, 'Collaborator not found');
+ }
+ return this.ok(res, collaborator);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * PUT /api/admin/collaborators/:id/hierarchy
+ * Update collaborator's manager (supervisor+ only).
+ */
+ async updateHierarchy(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const { reportsToId } = req.body;
+
+ const success = await this.collaboratorService.updateHierarchy(id, reportsToId || null);
+ if (!success) {
+ return this.notFound(res, 'Collaborator not found');
+ }
+ return this.ok(res, { message: 'Hierarchy updated successfully' });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/dashboard.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/dashboard.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..edbb83ca5a90e3e1d7b5b35fb34c5bfdaae27a56
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/dashboard.controller.ts
@@ -0,0 +1,37 @@
+/**
+ * @fileoverview Dashboard Controller
+ * Handles HTTP requests for dashboard/statistics endpoints.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { DashboardService } from '../services/dashboard.service';
+import { BaseController } from './base.controller';
+
+/**
+ * Controller for dashboard endpoints.
+ * Provides aggregated statistics and activity data.
+ */
+export class DashboardController extends BaseController {
+ private dashboardService: DashboardService;
+
+ constructor() {
+ super();
+ this.dashboardService = new DashboardService();
+ }
+
+ /**
+ * GET /api/dashboard
+ * Retrieves dashboard data including statistics and activity graphs.
+ */
+ public getDashboardData = async (req: Request, res: Response) => {
+ try {
+ const data = await this.dashboardService.getDashboardData();
+ return this.ok(res, data);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ };
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/organization.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/organization.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9887547c0e150fd9240d9adcf231ff7a70356e70
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/organization.controller.ts
@@ -0,0 +1,90 @@
+/**
+ * @fileoverview Organization Controller
+ * API endpoints for organization management.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { OrganizationService } from '../services/organization.service';
+import { AuthenticatedRequest } from '../middleware/auth.middleware';
+
+/**
+ * Controller for organization endpoints.
+ */
+export class OrganizationController extends BaseController {
+ private organizationService: OrganizationService;
+
+ constructor() {
+ super();
+ this.organizationService = new OrganizationService();
+ }
+
+ /**
+ * GET /api/organization
+ * Get the default organization (public).
+ */
+ async getDefault(req: Request, res: Response) {
+ try {
+ const org = await this.organizationService.getDefault();
+ if (!org) {
+ return this.notFound(res, 'No organization found');
+ }
+ return this.ok(res, org);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/organization/:id
+ * Get organization by ID.
+ */
+ async getById(req: Request, res: Response) {
+ try {
+ const { id } = req.params;
+ const org = await this.organizationService.getById(id);
+ if (!org) {
+ return this.notFound(res, 'Organization not found');
+ }
+ return this.ok(res, org);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/admin/organization/:id/stats
+ * Get organization with statistics (admin only).
+ */
+ async getWithStats(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const org = await this.organizationService.getWithStats(id);
+ if (!org) {
+ return this.notFound(res, 'Organization not found');
+ }
+ return this.ok(res, org);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * PUT /api/admin/organization/:id
+ * Update organization (admin only).
+ */
+ async update(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const org = await this.organizationService.update(id, req.body);
+ if (!org) {
+ return this.notFound(res, 'Organization not found');
+ }
+ return this.ok(res, org);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/page.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/page.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..821e1b531e9fa1abf2340287d532126aa6037d0a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/page.controller.ts
@@ -0,0 +1,354 @@
+/**
+ * @fileoverview Page Controller
+ * @description REST API controller for CMS page management with SEO support.
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { PageService } from '../services/page.service';
+import { PageType } from '../database/entities/page.entity';
+
+const pageService = new PageService();
+
+/**
+ * @swagger
+ * /api/pages:
+ * get:
+ * summary: Get all published pages
+ * tags: [Pages]
+ * responses:
+ * 200:
+ * description: List of published pages with SEO data
+ */
+export async function getAllPages(req: Request, res: Response): Promise {
+ try {
+ const pages = await pageService.getAllPublishedPages();
+ res.json(pages);
+ } catch (error) {
+ console.error('Error fetching pages:', error);
+ res.status(500).json({ error: 'Failed to fetch pages' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/pages/{slug}:
+ * get:
+ * summary: Get page by slug
+ * tags: [Pages]
+ * parameters:
+ * - in: path
+ * name: slug
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 200:
+ * description: Page with SEO metadata and structured data
+ * 404:
+ * description: Page not found
+ */
+export async function getPageBySlug(req: Request, res: Response): Promise {
+ try {
+ const { slug } = req.params;
+ const page = await pageService.getPageBySlug(slug);
+
+ if (!page) {
+ res.status(404).json({ error: 'Page not found' });
+ return;
+ }
+
+ res.json(page);
+ } catch (error) {
+ console.error('Error fetching page:', error);
+ res.status(500).json({ error: 'Failed to fetch page' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/pages/type/{pageType}:
+ * get:
+ * summary: Get pages by type
+ * tags: [Pages]
+ * parameters:
+ * - in: path
+ * name: pageType
+ * required: true
+ * schema:
+ * type: string
+ * enum: [home, about, blog, project, team, contact, custom]
+ * responses:
+ * 200:
+ * description: List of pages of specified type
+ */
+export async function getPagesByType(req: Request, res: Response): Promise {
+ try {
+ const { pageType } = req.params;
+ const pages = await pageService.getPagesByType(pageType as PageType);
+ res.json(pages);
+ } catch (error) {
+ console.error('Error fetching pages by type:', error);
+ res.status(500).json({ error: 'Failed to fetch pages' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/admin/pages:
+ * get:
+ * summary: Get all pages (admin)
+ * tags: [Pages, Admin]
+ * security:
+ * - bearerAuth: []
+ * responses:
+ * 200:
+ * description: List of all pages including unpublished
+ */
+export async function getAllPagesAdmin(req: Request, res: Response): Promise {
+ try {
+ const pages = await pageService.getAllPages();
+ res.json(pages);
+ } catch (error) {
+ console.error('Error fetching all pages:', error);
+ res.status(500).json({ error: 'Failed to fetch pages' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/admin/pages:
+ * post:
+ * summary: Create new page
+ * tags: [Pages, Admin]
+ * security:
+ * - bearerAuth: []
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - slug
+ * - title
+ * - content
+ * responses:
+ * 201:
+ * description: Page created successfully
+ * 400:
+ * description: Invalid input or slug already exists
+ */
+export async function createPage(req: Request, res: Response): Promise {
+ try {
+ const { slug, title, content, pageType, isPublished, seoMeta, structuredData } = req.body;
+
+ // Validate required fields
+ if (!slug || !title || !content) {
+ res.status(400).json({ error: 'Missing required fields: slug, title, content' });
+ return;
+ }
+
+ // Check if slug is available
+ const slugAvailable = await pageService.isSlugAvailable(slug);
+ if (!slugAvailable) {
+ res.status(400).json({ error: 'Slug already exists' });
+ return;
+ }
+
+ const authorId = (req as any).user?.id; // From auth middleware
+
+ const page = await pageService.createPage({
+ slug,
+ title,
+ content,
+ pageType,
+ isPublished,
+ authorId,
+ seoMeta,
+ structuredData
+ });
+
+ res.status(201).json(page);
+ } catch (error) {
+ console.error('Error creating page:', error);
+ res.status(500).json({ error: 'Failed to create page' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/admin/pages/{id}:
+ * put:
+ * summary: Update page
+ * tags: [Pages, Admin]
+ * security:
+ * - bearerAuth: []
+ * parameters:
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 200:
+ * description: Page updated successfully
+ * 404:
+ * description: Page not found
+ */
+export async function updatePage(req: Request, res: Response): Promise {
+ try {
+ const { id } = req.params;
+ const updates = req.body;
+
+ // If updating slug, check availability
+ if (updates.slug) {
+ const slugAvailable = await pageService.isSlugAvailable(updates.slug, id);
+ if (!slugAvailable) {
+ res.status(400).json({ error: 'Slug already exists' });
+ return;
+ }
+ }
+
+ const page = await pageService.updatePage(id, updates);
+
+ if (!page) {
+ res.status(404).json({ error: 'Page not found' });
+ return;
+ }
+
+ res.json(page);
+ } catch (error) {
+ console.error('Error updating page:', error);
+ res.status(500).json({ error: 'Failed to update page' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/admin/pages/{id}:
+ * delete:
+ * summary: Delete page
+ * tags: [Pages, Admin]
+ * security:
+ * - bearerAuth: []
+ * parameters:
+ * - in: path
+ * name: id
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 204:
+ * description: Page deleted successfully
+ * 404:
+ * description: Page not found
+ */
+export async function deletePage(req: Request, res: Response): Promise {
+ try {
+ const { id } = req.params;
+ const success = await pageService.deletePage(id);
+
+ if (!success) {
+ res.status(404).json({ error: 'Page not found' });
+ return;
+ }
+
+ res.status(204).send();
+ } catch (error) {
+ console.error('Error deleting page:', error);
+ res.status(500).json({ error: 'Failed to delete page' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/admin/pages/{pageId}/seo:
+ * put:
+ * summary: Update SEO metadata for a page
+ * tags: [Pages, Admin, SEO]
+ * security:
+ * - bearerAuth: []
+ * parameters:
+ * - in: path
+ * name: pageId
+ * required: true
+ * schema:
+ * type: string
+ * responses:
+ * 200:
+ * description: SEO metadata updated successfully
+ * 404:
+ * description: Page not found
+ */
+export async function updatePageSeo(req: Request, res: Response): Promise {
+ try {
+ const { pageId } = req.params;
+ const seoData = req.body;
+
+ const seoMeta = await pageService.updateSeoMeta(pageId, seoData);
+
+ if (!seoMeta) {
+ res.status(404).json({ error: 'Page not found' });
+ return;
+ }
+
+ res.json(seoMeta);
+ } catch (error) {
+ console.error('Error updating SEO metadata:', error);
+ res.status(500).json({ error: 'Failed to update SEO metadata' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/admin/pages/{pageId}/structured-data:
+ * post:
+ * summary: Add structured data to a page
+ * tags: [Pages, Admin, SEO]
+ * security:
+ * - bearerAuth: []
+ * parameters:
+ * - in: path
+ * name: pageId
+ * required: true
+ * schema:
+ * type: string
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * required:
+ * - schemaType
+ * - schemaData
+ * responses:
+ * 201:
+ * description: Structured data added successfully
+ * 404:
+ * description: Page not found
+ */
+export async function addStructuredData(req: Request, res: Response): Promise {
+ try {
+ const { pageId } = req.params;
+ const { schemaType, schemaData } = req.body;
+
+ if (!schemaType || !schemaData) {
+ res.status(400).json({ error: 'Missing required fields: schemaType, schemaData' });
+ return;
+ }
+
+ const structuredData = await pageService.addStructuredData(pageId, schemaType, schemaData);
+
+ if (!structuredData) {
+ res.status(404).json({ error: 'Page not found' });
+ return;
+ }
+
+ res.status(201).json(structuredData);
+ } catch (error) {
+ console.error('Error adding structured data:', error);
+ res.status(500).json({ error: 'Failed to add structured data' });
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/profile.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/profile.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..853447dd7968346373fe7e3936bf4267ff71d422
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/profile.controller.ts
@@ -0,0 +1,35 @@
+/**
+ * @fileoverview Profile Controller
+ * Handles HTTP requests for profile/contact info endpoints.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { ProfileService } from '../services/profile.service';
+import { BaseController } from './base.controller';
+
+const profileService = new ProfileService();
+
+/**
+ * Controller for profile endpoints.
+ * Provides access to portfolio owner's personal information.
+ */
+export class ProfileController extends BaseController {
+ /**
+ * GET /api/profile
+ * Retrieves the portfolio owner's profile information.
+ */
+ async getProfile(req: Request, res: Response) {
+ try {
+ const profile = await profileService.getProfile();
+ if (!profile) {
+ return this.notFound(res, 'Profile not found');
+ }
+ return this.ok(res, profile);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/project-presentation.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/project-presentation.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..18d6aa858f3d24a2c825a60a3d04a2a7d8d364d2
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/project-presentation.controller.ts
@@ -0,0 +1,35 @@
+import { Request, Response } from 'express';
+import { ProjectPresentationService } from '../services/project-presentation.service';
+import { BaseController } from './base.controller';
+
+export class ProjectPresentationController extends BaseController {
+ private service: ProjectPresentationService;
+
+ constructor() {
+ super();
+ this.service = new ProjectPresentationService();
+ }
+
+ getFullProject = async (req: Request, res: Response) => {
+ try {
+ const projectId = req.params.id;
+ const data = await this.service.getFullProject(projectId);
+ if (!data) {
+ return this.notFound(res, 'Project presentation not found');
+ }
+ return this.ok(res, data);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+
+ getAllProjects = async (req: Request, res: Response) => {
+ try {
+ const projects = await this.service.getAllProjectsSummary();
+ res.json(projects);
+ } catch (error) {
+ res.status(500).json({ message: 'Error fetching projects', error });
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/project.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/project.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..52261096c84b18f21159687bc66305b0be003fdb
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/project.controller.ts
@@ -0,0 +1,63 @@
+/**
+ * @fileoverview Project Controller
+ * Handles HTTP requests for project-related endpoints.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { ProjectService } from '../services/project.service';
+import { BaseController } from './base.controller';
+
+const projectService = new ProjectService();
+
+/**
+ * Controller for project endpoints.
+ * Provides CRUD operations for portfolio projects.
+ */
+export class ProjectController extends BaseController {
+ /**
+ * GET /api/projects
+ * Retrieves all projects with relations.
+ */
+ async getAllProjects(req: Request, res: Response) {
+ try {
+ const projects = await projectService.getAllProjects();
+ return this.ok(res, projects);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+
+ /**
+ * GET /api/projects/featured
+ * Retrieves featured projects for homepage carousel.
+ */
+ async getFeaturedProjects(req: Request, res: Response) {
+ try {
+ const projects = await projectService.getFeaturedProjects();
+ return this.ok(res, projects);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+
+ /**
+ * GET /api/projects/:id
+ * Retrieves a single project by ID or slug.
+ * Supports both UUID format and URL-friendly slugs (e.g., 'ark-alliance').
+ */
+ async getProjectById(req: Request, res: Response) {
+ try {
+ const idOrSlug = req.params.id;
+ const project = await projectService.getProjectByIdOrSlug(idOrSlug);
+ if (!project) {
+ return this.notFound(res, 'Project not found');
+ }
+ return this.ok(res, project);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/resume.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/resume.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5151ded78b6299fb53d8f40d52e43b8335056da2
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/resume.controller.ts
@@ -0,0 +1,34 @@
+/**
+ * @fileoverview Resume Controller
+ * Handles HTTP requests for Resume endpoints.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { ResumeService } from '../services/resume.service';
+import { BaseController } from './base.controller';
+
+const resumeService = new ResumeService();
+
+/**
+ * Controller for Resume endpoints.
+ * Provides access to education, experience, and skills data.
+ */
+export class ResumeController extends BaseController {
+ /**
+ * GET /api/resume
+ * Retrieves complete Resume data including education, experience, and skills.
+ * @query userId - Optional user ID to fetch resume for specific user
+ */
+ getResume = async (req: Request, res: Response) => {
+ try {
+ const userId = req.query.userId as string | undefined;
+ const resume = await resumeService.getResume(userId);
+ return this.ok(res, resume);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/site-settings.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/site-settings.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5cd15bf879c8d35d59f785c115e5b4323423f86d
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/site-settings.controller.ts
@@ -0,0 +1,99 @@
+/**
+ * @fileoverview Site Settings Controller
+ * @description REST API controller for global site configuration.
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { SiteSettingsService } from '../services/site-settings.service';
+
+const siteSettingsService = new SiteSettingsService();
+
+/**
+ * @swagger
+ * /api/site-settings:
+ * get:
+ * summary: Get site settings
+ * tags: [Settings]
+ * responses:
+ * 200:
+ * description: Global site settings
+ */
+export async function getSettings(req: Request, res: Response): Promise {
+ try {
+ const settings = await siteSettingsService.getSettings();
+ res.json(settings);
+ } catch (error) {
+ console.error('Error fetching site settings:', error);
+ res.status(500).json({ error: 'Failed to fetch site settings' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/admin/site-settings:
+ * put:
+ * summary: Update site settings
+ * tags: [Settings, Admin]
+ * security:
+ * - bearerAuth: []
+ * requestBody:
+ * required: true
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * responses:
+ * 200:
+ * description: Settings updated successfully
+ */
+export async function updateSettings(req: Request, res: Response): Promise {
+ try {
+ const updates = req.body;
+ const settings = await siteSettingsService.updateSettings(updates);
+ res.json(settings);
+ } catch (error) {
+ console.error('Error updating site settings:', error);
+ res.status(500).json({ error: 'Failed to update site settings' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/seo/organization-schema:
+ * get:
+ * summary: Get Organization JSON-LD schema
+ * tags: [SEO]
+ * responses:
+ * 200:
+ * description: Organization schema in JSON-LD format
+ */
+export async function getOrganizationSchema(req: Request, res: Response): Promise {
+ try {
+ const schema = await siteSettingsService.getOrganizationSchema();
+ res.json(schema);
+ } catch (error) {
+ console.error('Error generating organization schema:', error);
+ res.status(500).json({ error: 'Failed to generate organization schema' });
+ }
+}
+
+/**
+ * @swagger
+ * /api/seo/website-schema:
+ * get:
+ * summary: Get WebSite JSON-LD schema
+ * tags: [SEO]
+ * responses:
+ * 200:
+ * description: WebSite schema in JSON-LD format
+ */
+export async function getWebSiteSchema(req: Request, res: Response): Promise {
+ try {
+ const schema = await siteSettingsService.getWebSiteSchema();
+ res.json(schema);
+ } catch (error) {
+ console.error('Error generating website schema:', error);
+ res.status(500).json({ error: 'Failed to generate website schema' });
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/sitemap.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/sitemap.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e8b818d144df517922105c2cbae626b450014162
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/sitemap.controller.ts
@@ -0,0 +1,155 @@
+/**
+ * @fileoverview Sitemap & Robots Controller
+ * @description Generates dynamic sitemap.xml and robots.txt for SEO crawlers.
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { PageService } from '../services/page.service';
+import { ProjectService } from '../services/project.service';
+import { SiteSettingsService } from '../services/site-settings.service';
+
+const pageService = new PageService();
+const projectService = new ProjectService();
+const siteSettingsService = new SiteSettingsService();
+
+/**
+ * Generate sitemap JSON for frontend sitemap module
+ * @swagger
+ * /api/sitemap:
+ * get:
+ * summary: Get sitemap data
+ * tags: [SEO]
+ * responses:
+ * 200:
+ * description: Array of URL objects for sitemap
+ */
+export async function getSitemapData(req: Request, res: Response): Promise {
+ try {
+ const settings = await siteSettingsService.getSettings();
+ const baseUrl = settings.siteUrl;
+
+ const urls: Array<{
+ loc: string;
+ lastmod?: string;
+ changefreq?: string;
+ priority?: number;
+ }> = [];
+
+ // Add pages
+ const pages = await pageService.getAllPublishedPages();
+ for (const page of pages) {
+ urls.push({
+ loc: `${baseUrl}/${page.slug}`,
+ lastmod: page.updatedAt.toISOString(),
+ changefreq: page.pageType === 'home' ? 'weekly' : 'monthly',
+ priority: page.pageType === 'home' ? 1.0 : 0.8
+ });
+ }
+
+ // Add projects
+ const projects = await projectService.getAllProjects();
+ for (const project of projects) {
+ const slug = project.title
+ .toLowerCase()
+ .replace(/\./g, '-')
+ .replace(/\s+/g, '-')
+ .replace(/-+/g, '-');
+
+ urls.push({
+ loc: `${baseUrl}/projects/${slug}`,
+ lastmod: project.endDate ? new Date(project.endDate).toISOString() : new Date().toISOString(),
+ changefreq: 'monthly',
+ priority: project.isFeatured ? 0.9 : 0.7
+ });
+ }
+
+ // Add static pages
+ const staticPages = [
+ { loc: `${baseUrl}/`, priority: 1.0, changefreq: 'weekly' },
+ { loc: `${baseUrl}/projects`, priority: 0.9, changefreq: 'weekly' },
+ { loc: `${baseUrl}/team`, priority: 0.8, changefreq: 'monthly' },
+ { loc: `${baseUrl}/contact`, priority: 0.7, changefreq: 'monthly' }
+ ];
+
+ urls.push(...staticPages);
+
+ res.json(urls);
+ } catch (error) {
+ console.error('Error generating sitemap:', error);
+ res.status(500).json({ error: 'Failed to generate sitemap' });
+ }
+}
+
+/**
+ * Generate robots.txt with AI crawler allowlist
+ * @swagger
+ * /robots.txt:
+ * get:
+ * summary: Get robots.txt
+ * tags: [SEO]
+ * responses:
+ * 200:
+ * description: robots.txt content
+ * content:
+ * text/plain:
+ * schema:
+ * type: string
+ */
+export async function getRobotsTxt(req: Request, res: Response): Promise {
+ try {
+ const settings = await siteSettingsService.getSettings();
+ const sitemapUrl = `${settings.siteUrl}/sitemap.xml`;
+
+ const robotsTxt = `# Ark Alliance CMS - SEO & AEO Optimized
+# Allow all standard search engines and AI crawlers
+
+User-agent: *
+Allow: /
+
+# Google
+User-agent: Googlebot
+Allow: /
+
+# Bing/Yahoo
+User-agent: Bingbot
+Allow: /
+
+# OpenAI (ChatGPT Search)
+User-agent: GPTBot
+Allow: /
+
+# Anthropic (Claude)
+User-agent: ClaudeBot
+Allow: /
+
+User-agent: claude-web
+Allow: /
+
+User-agent: anthropic-ai
+Allow: /
+
+# Perplexity
+User-agent: PerplexityBot
+Allow: /
+
+# Other AI Crawlers
+User-agent: Bytespider
+Allow: /
+
+User-agent: CCBot
+Allow: /
+
+# Google-Extended (Gemini AI) - implicit allow via absence of Disallow
+
+# Sitemap
+Sitemap: ${sitemapUrl}
+`;
+
+ res.setHeader('Content-Type', 'text/plain');
+ res.send(robotsTxt);
+ } catch (error) {
+ console.error('Error generating robots.txt:', error);
+ res.status(500).send('# Error generating robots.txt');
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/task.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/task.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a7ec0a38a5e297256fc67717e47da1dec228fc30
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/task.controller.ts
@@ -0,0 +1,174 @@
+/**
+ * @fileoverview Task Controller
+ * API endpoints for task/accomplishment management.
+ *
+ * Routes:
+ * - GET /api/tasks/public/:collaboratorId - Public accomplishments (Achieved + Lessons)
+ * - GET /api/tasks/public/:collaboratorId/summary - Public summary stats
+ * - GET /api/admin/tasks/:collaboratorId - All tasks (internal)
+ * - GET /api/admin/tasks/detail/:id - Single task detail
+ * - POST /api/admin/tasks/:collaboratorId - Create task
+ * - PUT /api/admin/tasks/:id - Update task
+ * - POST /api/admin/tasks/:id/rate - Add peer rating
+ * - DELETE /api/admin/tasks/:id - Delete task
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { TaskService } from '../services/task.service';
+import { AuthenticatedRequest } from '../middleware/auth.middleware';
+
+/**
+ * Controller for task/accomplishment endpoints.
+ * Separates public (recognition) and admin (management) routes.
+ */
+export class TaskController extends BaseController {
+ private taskService: TaskService;
+
+ constructor() {
+ super();
+ this.taskService = new TaskService();
+ }
+
+ // ═══════════════════════════════════════════════════════════════════════
+ // PUBLIC ROUTES (Recognition - External Resume View)
+ // ═══════════════════════════════════════════════════════════════════════
+
+ /**
+ * GET /api/tasks/public/:collaboratorId
+ * Get public accomplishments for a collaborator.
+ * Only returns Achieved tasks and Mistakes with lessons learned.
+ */
+ async getPublicTasks(req: Request, res: Response) {
+ try {
+ const { collaboratorId } = req.params;
+ const tasks = await this.taskService.getPublicTasks(collaboratorId);
+ return this.ok(res, tasks);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/tasks/public/:collaboratorId/summary
+ * Get public accomplishments summary statistics.
+ */
+ async getPublicSummary(req: Request, res: Response) {
+ try {
+ const { collaboratorId } = req.params;
+ const summary = await this.taskService.getPublicSummary(collaboratorId);
+ return this.ok(res, summary);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ // ═══════════════════════════════════════════════════════════════════════
+ // ADMIN ROUTES (Task Management - Authenticated)
+ // ═══════════════════════════════════════════════════════════════════════
+
+ /**
+ * GET /api/admin/tasks/:collaboratorId
+ * Get all tasks for a collaborator (internal view).
+ * Includes all statuses: backlog, ongoing, achieved, mistake.
+ */
+ async getAllTasks(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { collaboratorId } = req.params;
+ const tasks = await this.taskService.getAllTasks(collaboratorId);
+ return this.ok(res, tasks);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/admin/tasks/detail/:id
+ * Get a single task by ID.
+ */
+ async getById(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const task = await this.taskService.getById(id);
+ if (!task) {
+ return this.notFound(res, 'Task not found');
+ }
+ return this.ok(res, task);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * POST /api/admin/tasks/:collaboratorId
+ * Create a new task for a collaborator.
+ */
+ async create(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { collaboratorId } = req.params;
+ const task = await this.taskService.create(collaboratorId, req.body);
+ return this.ok(res, task);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * PUT /api/admin/tasks/:id
+ * Update a task.
+ */
+ async update(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const task = await this.taskService.update(id, req.body);
+ if (!task) {
+ return this.notFound(res, 'Task not found');
+ }
+ return this.ok(res, task);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * POST /api/admin/tasks/:id/rate
+ * Add a peer rating to a task.
+ */
+ async addRating(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const { rating } = req.body;
+
+ if (typeof rating !== 'number' || rating < 1 || rating > 5) {
+ return this.clientError(res, 'Rating must be a number between 1 and 5');
+ }
+
+ const task = await this.taskService.addRating(id, rating);
+ if (!task) {
+ return this.notFound(res, 'Task not found');
+ }
+ return this.ok(res, task);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * DELETE /api/admin/tasks/:id
+ * Delete a task.
+ */
+ async delete(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const success = await this.taskService.delete(id);
+ if (!success) {
+ return this.notFound(res, 'Task not found');
+ }
+ return this.ok(res, { message: 'Task deleted successfully' });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/technology.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/technology.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ab9b0aa9dd5237675ff70ef95892658f4e0ff4ae
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/technology.controller.ts
@@ -0,0 +1,169 @@
+/**
+ * @fileoverview Technology API Controller
+ * Provides endpoints for retrieving technology master data
+ *
+ * @module controllers/technology.controller
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import * as fs from 'fs';
+import * as path from 'path';
+import { TechnologiesResponseDto, TechnologyDto, TechnologyCategoryDto } from '@arkalliance/startupcms-ai-share';
+
+/**
+ * In-memory cache for technologies data
+ * Loaded once on first request to avoid repeated file reads
+ */
+let technologiesCache: TechnologiesResponseDto | null = null;
+
+/**
+ * Load technologies from JSON file
+ * Caches result for subsequent requests
+ */
+function loadTechnologies(): TechnologiesResponseDto {
+ if (technologiesCache) {
+ return technologiesCache;
+ }
+
+ const dataPath = path.join(__dirname, '../database/InitDbAsset/JsonDatas/technologies.json');
+ const rawData = fs.readFileSync(dataPath, 'utf-8');
+ const data = JSON.parse(rawData);
+
+ // Build response with categories and flat technology list
+ const categories: TechnologyCategoryDto[] = data.categories.map((cat: any) => ({
+ id: cat.id,
+ name: cat.name,
+ description: cat.description,
+ order: cat.order,
+ technologies: data.technologies
+ .filter((tech: any) => tech.category === cat.id)
+ .map((tech: any) => ({
+ key: tech.key,
+ name: tech.name,
+ label: tech.label,
+ category: tech.category,
+ description: tech.description,
+ icon: tech.icon,
+ color: tech.color,
+ website: tech.website,
+ versions: tech.versions
+ } as TechnologyDto))
+ }));
+
+ const allTechnologies: TechnologyDto[] = data.technologies.map((tech: any) => ({
+ key: tech.key,
+ name: tech.name,
+ label: tech.label,
+ category: tech.category,
+ description: tech.description,
+ icon: tech.icon,
+ color: tech.color,
+ website: tech.website,
+ versions: tech.versions
+ }));
+
+ technologiesCache = {
+ categories,
+ technologies: allTechnologies
+ };
+
+ return technologiesCache;
+}
+
+/**
+ * GET /api/technologies
+ * Returns all technologies grouped by categories
+ *
+ * @param req - Express request
+ * @param res - Express response
+ *
+ * @swagger
+ * /api/technologies:
+ * get:
+ * summary: Get all technologies
+ * tags: [Technologies]
+ * responses:
+ * 200:
+ * description: Technologies grouped by categories
+ * content:
+ * application/json:
+ * schema:
+ * type: object
+ * properties:
+ * categories:
+ * type: array
+ * items:
+ * $ref: '#/components/schemas/TechnologyCategory'
+ * technologies:
+ * type: array
+ * items:
+ * $ref: '#/components/schemas/Technology'
+ */
+export const getAllTechnologies = async (req: Request, res: Response): Promise => {
+ try {
+ const data = loadTechnologies();
+ res.json(data);
+ } catch (error) {
+ console.error('Error loading technologies:', error);
+ res.status(500).json({ error: 'Failed to load technologies' });
+ }
+};
+
+/**
+ * GET /api/technologies/:key
+ * Returns a single technology by its key
+ *
+ * @param req - Express request with key parameter
+ * @param res - Express response
+ *
+ * @swagger
+ * /api/technologies/{key}:
+ * get:
+ * summary: Get technology by key
+ * tags: [Technologies]
+ * parameters:
+ * - in: path
+ * name: key
+ * required: true
+ * schema:
+ * type: string
+ * description: Technology key (e.g., 'react', 'typescript')
+ * responses:
+ * 200:
+ * description: Technology details
+ * content:
+ * application/json:
+ * schema:
+ * $ref: '#/components/schemas/Technology'
+ * 404:
+ * description: Technology not found
+ */
+export const getTechnologyByKey = async (req: Request, res: Response): Promise => {
+ try {
+ const { key } = req.params;
+ const data = loadTechnologies();
+
+ const technology = data.technologies.find(t => t.key === key);
+
+ if (!technology) {
+ res.status(404).json({ error: `Technology '${key}' not found` });
+ return;
+ }
+
+ res.json(technology);
+ } catch (error) {
+ console.error('Error finding technology:', error);
+ res.status(500).json({ error: 'Failed to find technology' });
+ }
+};
+
+/**
+ * Clear cache (for development/testing)
+ * Not exposed as public endpoint
+ */
+export const clearCache = (): void => {
+ technologiesCache = null;
+};
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/theme.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/theme.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..aeb54a70c42bc4ef073d5e68ba53daf0157087af
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/theme.controller.ts
@@ -0,0 +1,65 @@
+/**
+ * @fileoverview Theme Controller
+ * Handles HTTP requests for theme-related endpoints.
+ *
+ * @module controllers/theme.controller
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { ThemeService } from '../services/theme.service';
+import { BaseController } from './base.controller';
+
+const themeService = new ThemeService();
+
+/**
+ * Controller for theme endpoints.
+ * Provides read-only access to themes for frontend consumption.
+ */
+export class ThemeController extends BaseController {
+ /**
+ * GET /api/themes
+ * Retrieves all active themes (without CSS content for performance).
+ */
+ async listThemes(req: Request, res: Response) {
+ try {
+ const themes = await themeService.listThemes();
+ return this.ok(res, themes);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+
+ /**
+ * GET /api/themes/default
+ * Retrieves the default theme with full CSS content.
+ */
+ async getDefaultTheme(req: Request, res: Response) {
+ try {
+ const theme = await themeService.getDefaultTheme();
+ if (!theme) {
+ return this.notFound(res, 'No default theme configured');
+ }
+ return this.ok(res, theme);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+
+ /**
+ * GET /api/themes/:slug
+ * Retrieves a specific theme by slug with full CSS content.
+ */
+ async getThemeBySlug(req: Request, res: Response) {
+ try {
+ const { slug } = req.params;
+ const theme = await themeService.getThemeBySlug(slug);
+ if (!theme) {
+ return this.notFound(res, `Theme '${slug}' not found`);
+ }
+ return this.ok(res, theme);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/user-management.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/user-management.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ea4e5bc70c1b0961c27e9bde3094890d2ae548cd
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/user-management.controller.ts
@@ -0,0 +1,218 @@
+/**
+ * @fileoverview User Management Controller
+ * API endpoints for admin user and role management.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { BaseController } from './base.controller';
+import { RoleService } from '../services/role.service';
+import { AuthenticatedRequest } from '../middleware/auth.middleware';
+import { Role } from '@arkalliance/startupcms-ai-share';
+import { AppDataSource } from '../config/database';
+import { User } from '../database/entities/user.entity';
+
+/**
+ * Controller for user management endpoints.
+ */
+export class UserManagementController extends BaseController {
+ private roleService: RoleService;
+
+ constructor() {
+ super();
+ this.roleService = new RoleService();
+ }
+
+ /**
+ * GET /api/admin/users
+ * List all users (supervisor+ only).
+ */
+ async list(req: AuthenticatedRequest, res: Response) {
+ try {
+ const userRepo = AppDataSource.getRepository(User);
+ const users = await userRepo.find({
+ relations: ['userRoles'],
+ order: { createdAt: 'DESC' }
+ });
+
+ const result = users.map(user => ({
+ id: user.id,
+ username: user.username,
+ email: user.email,
+ avatarUrl: user.avatarUrl,
+ roles: user.roles,
+ isActive: user.isActive,
+ emailConfirmed: user.emailConfirmed,
+ lastLogin: user.lastLogin?.toISOString(),
+ isLocked: user.isLocked,
+ createdAt: user.createdAt.toISOString()
+ }));
+
+ return this.ok(res, result);
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * GET /api/admin/users/:id
+ * Get user details (supervisor+ only).
+ */
+ async getById(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const userRepo = AppDataSource.getRepository(User);
+ const user = await userRepo.findOne({
+ where: { id },
+ relations: ['userRoles']
+ });
+
+ if (!user) {
+ return this.notFound(res, 'User not found');
+ }
+
+ return this.ok(res, {
+ id: user.id,
+ username: user.username,
+ email: user.email,
+ avatarUrl: user.avatarUrl,
+ roles: user.roles,
+ isActive: user.isActive,
+ emailConfirmed: user.emailConfirmed,
+ lastLogin: user.lastLogin?.toISOString(),
+ failedLoginAttempts: user.failedLoginAttempts,
+ isLocked: user.isLocked,
+ lockoutUntil: user.lockoutUntil?.toISOString(),
+ collaboratorId: user.collaboratorId,
+ createdAt: user.createdAt.toISOString(),
+ updatedAt: user.updatedAt.toISOString()
+ });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * POST /api/admin/users/:id/roles
+ * Assign a role to a user (supervisor+ only, with permission checks).
+ */
+ async assignRole(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const { role } = req.body;
+
+ if (!role || !Object.values(Role).includes(role)) {
+ return this.clientError(res, 'Invalid role specified');
+ }
+
+ const currentUser = req.user!;
+ const result = await this.roleService.assignRole(
+ id,
+ role,
+ currentUser.id,
+ currentUser.roles,
+ req.ip
+ );
+
+ if (!result.success) {
+ return this.forbidden(res, result.error || 'Failed to assign role');
+ }
+
+ return this.ok(res, { message: 'Role assigned successfully' });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * DELETE /api/admin/users/:id/roles/:role
+ * Revoke a role from a user (supervisor+ only, with permission checks).
+ */
+ async revokeRole(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id, role } = req.params;
+
+ if (!Object.values(Role).includes(role as Role)) {
+ return this.clientError(res, 'Invalid role specified');
+ }
+
+ const currentUser = req.user!;
+ const result = await this.roleService.revokeRole(
+ id,
+ role as Role,
+ currentUser.id,
+ currentUser.roles,
+ req.ip
+ );
+
+ if (!result.success) {
+ return this.forbidden(res, result.error || 'Failed to revoke role');
+ }
+
+ return this.ok(res, { message: 'Role revoked successfully' });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * POST /api/admin/users/:id/unlock
+ * Unlock a locked user account (admin only).
+ */
+ async unlockUser(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const { resetFailedAttempts = true } = req.body;
+
+ const userRepo = AppDataSource.getRepository(User);
+ const user = await userRepo.findOne({ where: { id } });
+
+ if (!user) {
+ return this.notFound(res, 'User not found');
+ }
+
+ user.lockoutUntil = undefined;
+ if (resetFailedAttempts) {
+ user.failedLoginAttempts = 0;
+ }
+ await userRepo.save(user);
+
+ return this.ok(res, { message: 'User account unlocked' });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * POST /api/admin/users/:id/avatar
+ * Update user avatar URL (admin only).
+ */
+ async updateAvatar(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+ const { avatarUrl } = req.body;
+
+ const userRepo = AppDataSource.getRepository(User);
+ const user = await userRepo.findOne({ where: { id } });
+
+ if (!user) {
+ return this.notFound(res, 'User not found');
+ }
+
+ user.avatarUrl = avatarUrl;
+ await userRepo.save(user);
+
+ return this.ok(res, {
+ id: user.id,
+ username: user.username,
+ avatarUrl: user.avatarUrl,
+ message: 'Avatar updated successfully'
+ });
+ } catch (error: any) {
+ return this.fail(res, error.message);
+ }
+ }
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/user-profile.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/user-profile.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8ff3188e83f53bdf4ff0f7950781f9f27c15bb28
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/user-profile.controller.ts
@@ -0,0 +1,371 @@
+/**
+ * @fileoverview User Profile Controller
+ * Complete CRUD operations for User with nested Collaborator and resume data.
+ * Includes avatar base64 conversion for API responses.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Request, Response } from 'express';
+import { AppDataSource } from '../config/database';
+import { User } from '../database/entities/user.entity';
+import { Collaborator } from '../database/entities/collaborator.entity';
+import { Experience } from '../database/entities/experience.entity';
+import { Education } from '../database/entities/education.entity';
+import { Skill } from '../database/entities/skill.entity';
+import { Language } from '../database/entities/language.entity';
+import { Hobby } from '../database/entities/hobby.entity';
+import { BusinessDomain } from '../database/entities/business-domain.entity';
+import { UserRole } from '../database/entities/user-role.entity';
+import { BaseController } from './base.controller';
+import { AuthenticatedRequest } from '../middleware/auth.middleware';
+import bcrypt from 'bcryptjs';
+import { convertImageToBase64 } from '../utils/image-converter';
+
+/**
+ * Controller for comprehensive user profile management
+ */
+export class UserProfileController extends BaseController {
+
+ /**
+ * GET /api/users/:id/profile
+ * Get complete user profile with all nested data and avatar as base64
+ */
+ async getProfile(req: AuthenticatedRequest, res: Response) {
+ try {
+ const { id } = req.params;
+
+ const userRepo = AppDataSource.getRepository(User);
+ const user = await userRepo.findOne({
+ where: { id },
+ relations: [
+ 'userRoles',
+ 'experiences',
+ 'educations',
+ 'skills',
+ 'languages',
+ 'hobbies',
+ 'businessDomains'
+ ]
+ });
+
+ if (!user) {
+ return this.notFound(res, 'User not found');
+ }
+
+ // Load collaborator if linked
+ let collaborator = null;
+ if (user.collaboratorId) {
+ const collabRepo = AppDataSource.getRepository(Collaborator);
+ collaborator = await collabRepo.findOne({
+ where: { id: user.collaboratorId },
+ relations: ['reportsTo', 'directReports', 'organization']
+ });
+ }
+
+ // Convert avatar to base64
+ let avatarBase64: string | null = null;
+ if (user.avatarUrl) {
+ try {
+ avatarBase64 = await convertImageToBase64(user.avatarUrl);
+ } catch (error) {
+ console.warn(`Failed to convert avatar for user ${id}:`, error);
+ }
+ }
+
+ // Build response
+ const response = {
+ // User fields
+ id: user.id,
+ username: user.username,
+ email: user.email,
+ firstName: user.firstName,
+ lastName: user.lastName,
+ fullName: user.fullName,
+ bio: user.bio,
+ title: user.title,
+ avatarUrl: user.avatarUrl,
+ avatarBase64, // Base64-encoded avatar
+ linkedinUrl: user.linkedinUrl,
+ githubUrl: user.githubUrl,
+ twitterUrl: user.twitterUrl,
+
+ // Account status
+ isActive: user.isActive,
+ emailConfirmed: user.emailConfirmed,
+ lastLogin: user.lastLogin?.toISOString(),
+
+ // Roles
+ roles: user.roles,
+
+ // Linked collaborator
+ collaboratorId: user.collaboratorId,
+ collaborator: collaborator ? {
+ id: collaborator.id,
+ firstName: collaborator.firstName,
+ lastName: collaborator.lastName,
+ fullName: collaborator.fullName,
+ email: collaborator.email,
+ position: collaborator.position,
+ department: collaborator.department,
+ bio: collaborator.bio,
+ avatarUrl: collaborator.avatarUrl,
+ linkedinUrl: collaborator.linkedinUrl,
+ githubUrl: collaborator.githubUrl,
+ phone: collaborator.phone,
+ hireDate: collaborator.hireDate?.toISOString(),
+ organizationId: collaborator.organizationId,
+ reportsToId: collaborator.reportsToId,
+ reportsTo: collaborator.reportsTo ? {
+ id: collaborator.reportsTo.id,
+ fullName: collaborator.reportsTo.fullName,
+ position: collaborator.reportsTo.position
+ } : null
+ } : null,
+
+ // Resume data
+ experiences: user.experiences.map(exp => ({
+ id: exp.id,
+ company: exp.company,
+ position: exp.position,
+ project: exp.project,
+ startDate: exp.startDate?.toISOString(),
+ endDate: exp.endDate?.toISOString(),
+ description: exp.description,
+ technologies: exp.technologies,
+ isHighlighted: exp.isHighlighted,
+ displayOrder: exp.displayOrder
+ })),
+
+ educations: user.educations.map(edu => ({
+ id: edu.id,
+ institution: edu.institution,
+ degree: edu.degree,
+ fieldOfStudy: edu.fieldOfStudy,
+ startDate: edu.startDate?.toISOString(),
+ endDate: edu.endDate?.toISOString(),
+ description: edu.description
+ })),
+
+ skills: user.skills.map(skill => ({
+ id: skill.id,
+ name: skill.name,
+ level: skill.level,
+ yearsOfExperience: skill.yearsOfExperience
+ })),
+
+ languages: user.languages.map(lang => ({
+ id: lang.id,
+ language: lang.language,
+ speaking: lang.speaking,
+ writing: lang.writing,
+ presenting: lang.presenting
+ })),
+
+ hobbies: user.hobbies.map(hobby => ({
+ id: hobby.id,
+ name: hobby.name,
+ description: hobby.description,
+ icon: hobby.icon,
+ displayOrder: hobby.displayOrder
+ })),
+
+ businessDomains: user.businessDomains.map(domain => ({
+ id: domain.id,
+ domain: domain.domain,
+ level: domain.level,
+ yearsOfExperience: domain.yearsOfExperience,
+ description: domain.description
+ })),
+
+ // Timestamps
+ createdAt: user.createdAt.toISOString(),
+ updatedAt: user.updatedAt.toISOString()
+ };
+
+ return this.ok(res, response);
+ } catch (error: any) {
+ console.error('Error fetching user profile:', error);
+ return this.fail(res, error.message);
+ }
+ }
+
+ /**
+ * POST /api/users/profile
+ * Create or update user with nested data
+ */
+ async createOrUpdateProfile(req: AuthenticatedRequest, res: Response) {
+ try {
+ const data = req.body;
+
+ return await AppDataSource.transaction(async (transactionalEntityManager) => {
+ const userRepo = transactionalEntityManager.getRepository(User);
+ const collaboratorRepo = transactionalEntityManager.getRepository(Collaborator);
+ const experienceRepo = transactionalEntityManager.getRepository(Experience);
+ const educationRepo = transactionalEntityManager.getRepository(Education);
+ const skillRepo = transactionalEntityManager.getRepository(Skill);
+ const languageRepo = transactionalEntityManager.getRepository(Language);
+ const hobbyRepo = transactionalEntityManager.getRepository(Hobby);
+ const domainRepo = transactionalEntityManager.getRepository(BusinessDomain);
+ const userRoleRepo = transactionalEntityManager.getRepository(UserRole);
+
+ // Find or create user
+ let user: User;
+ let isNewUser = false;
+
+ if (data.id) {
+ const existing = await userRepo.findOne({ where: { id: data.id } });
+ if (!existing) {
+ return this.notFound(res, 'User not found');
+ }
+ user = existing;
+ } else {
+ isNewUser = true;
+ user = userRepo.create();
+ }
+
+ // Update user fields
+ user.username = data.username || user.username;
+ user.email = data.email || user.email;
+ user.firstName = data.firstName !== undefined ? data.firstName : user.firstName;
+ user.lastName = data.lastName !== undefined ? data.lastName : user.lastName;
+ user.bio = data.bio !== undefined ? data.bio : user.bio;
+ user.title = data.title !== undefined ? data.title : user.title;
+ user.avatarUrl = data.avatarUrl !== undefined ? data.avatarUrl : user.avatarUrl;
+ user.linkedinUrl = data.linkedinUrl !== undefined ? data.linkedinUrl : user.linkedinUrl;
+ user.githubUrl = data.githubUrl !== undefined ? data.githubUrl : user.githubUrl;
+ user.twitterUrl = data.twitterUrl !== undefined ? data.twitterUrl : user.twitterUrl;
+
+ // Hash password if provided
+ if (data.password) {
+ user.passwordHash = await bcrypt.hash(data.password, 10);
+ }
+
+ await userRepo.save(user);
+
+ // Handle roles
+ if (data.roles && Array.isArray(data.roles)) {
+ // Remove existing roles
+ await userRoleRepo.delete({ userId: user.id });
+
+ // Add new roles
+ for (const role of data.roles) {
+ const userRole = userRoleRepo.create({
+ userId: user.id,
+ role
+ });
+ await userRoleRepo.save(userRole);
+ }
+ }
+
+ // Handle collaborator
+ if (data.collaborator) {
+ let collaborator: Collaborator;
+
+ if (data.collaborator.id) {
+ const existing = await collaboratorRepo.findOne({ where: { id: data.collaborator.id } });
+ if (!existing) {
+ return this.notFound(res, 'Collaborator not found');
+ }
+ collaborator = existing;
+ } else {
+ collaborator = collaboratorRepo.create();
+ }
+
+ // Update collaborator fields
+ Object.assign(collaborator, {
+ ...data.collaborator,
+ userId: user.id
+ });
+
+ await collaboratorRepo.save(collaborator);
+ user.collaboratorId = collaborator.id;
+ await userRepo.save(user);
+ }
+
+ // Handle experiences
+ if (data.experiences) {
+ // Delete existing
+ await experienceRepo.delete({ userId: user.id });
+
+ // Create new
+ for (const expData of data.experiences) {
+ const experience = experienceRepo.create({
+ ...expData,
+ userId: user.id
+ });
+ await experienceRepo.save(experience);
+ }
+ }
+
+ // Handle educations
+ if (data.educations) {
+ await educationRepo.delete({ userId: user.id });
+ for (const eduData of data.educations) {
+ const education = educationRepo.create({
+ ...eduData,
+ userId: user.id
+ });
+ await educationRepo.save(education);
+ }
+ }
+
+ // Handle skills
+ if (data.skills) {
+ await skillRepo.delete({ userId: user.id });
+ for (const skillData of data.skills) {
+ const skill = skillRepo.create({
+ ...skillData,
+ userId: user.id
+ });
+ await skillRepo.save(skill);
+ }
+ }
+
+ // Handle languages
+ if (data.languages) {
+ await languageRepo.delete({ userId: user.id });
+ for (const langData of data.languages) {
+ const language = languageRepo.create({
+ ...langData,
+ userId: user.id
+ });
+ await languageRepo.save(language);
+ }
+ }
+
+ // Handle hobbies
+ if (data.hobbies) {
+ await hobbyRepo.delete({ userId: user.id });
+ for (const hobbyData of data.hobbies) {
+ const hobby = hobbyRepo.create({
+ ...hobbyData,
+ userId: user.id
+ });
+ await hobbyRepo.save(hobby);
+ }
+ }
+
+ // Handle business domains
+ if (data.businessDomains) {
+ await domainRepo.delete({ userId: user.id });
+ for (const domainData of data.businessDomains) {
+ const domain = domainRepo.create({
+ ...domainData,
+ userId: user.id
+ });
+ await domainRepo.save(domain);
+ }
+ }
+
+ return this.ok(res, {
+ id: user.id,
+ message: isNewUser ? 'User profile created successfully' : 'User profile updated successfully'
+ });
+ });
+ } catch (error: any) {
+ console.error('Error creating/updating user profile:', error);
+ return this.fail(res, error.message);
+ }
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/widget.controller.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/widget.controller.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2d34eed371d8927cb7ba7cec92afb550bd54976a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/controllers/widget.controller.ts
@@ -0,0 +1,31 @@
+import { Request, Response } from 'express';
+import { WidgetService } from '../services/widget.service';
+import { BaseController } from './base.controller';
+
+export class WidgetController extends BaseController {
+ private service: WidgetService;
+
+ constructor() {
+ super();
+ this.service = new WidgetService();
+ }
+
+ getHomeWidgets = async (req: Request, res: Response) => {
+ try {
+ const widgets = await this.service.getHomeWidgets();
+ return this.ok(res, widgets);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+
+ getProjectWidgets = async (req: Request, res: Response) => {
+ try {
+ const widgets = await this.service.getProjectWidgets(req.params.projectId);
+ return this.ok(res, widgets);
+ } catch (error) {
+ return this.fail(res, error as Error);
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/business-domains.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/business-domains.json
new file mode 100644
index 0000000000000000000000000000000000000000..5c31888e36d1c5515b4cb3924d29e4db4fdef43e
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/business-domains.json
@@ -0,0 +1,72 @@
+[
+ {
+ "domain": "Logistics",
+ "level": "Expert",
+ "yearsOfExperience": 12,
+ "description": "Supply chain management, warehouse systems, TMS integration, delivery tracking, and last-mile logistics optimization.",
+ "icon": "Truck"
+ },
+ {
+ "domain": "Finance",
+ "level": "Expert",
+ "yearsOfExperience": 8,
+ "description": "Asset management, portfolio systems, trading platforms, regulatory compliance, and financial data integration.",
+ "icon": "TrendingUp"
+ },
+ {
+ "domain": "Trading",
+ "level": "Expert",
+ "yearsOfExperience": 5,
+ "description": "Algorithmic trading systems, market data processing, order management, and cryptocurrency platforms.",
+ "icon": "LineChart"
+ },
+ {
+ "domain": "Banking",
+ "level": "Advanced",
+ "yearsOfExperience": 3,
+ "description": "Core banking systems, payment processing, VoIP infrastructure for banking operations.",
+ "icon": "Building"
+ },
+ {
+ "domain": "Asset Management",
+ "level": "Expert",
+ "yearsOfExperience": 4,
+ "description": "Investment portfolio systems, fund management, asset position tracking, and regulatory reporting.",
+ "icon": "Briefcase"
+ },
+ {
+ "domain": "Steel Manufacturing",
+ "level": "Advanced",
+ "yearsOfExperience": 2,
+ "description": "Production planning, SAP ERP integration, supply chain for steel industry, and manufacturing logistics.",
+ "icon": "Factory"
+ },
+ {
+ "domain": "Retail",
+ "level": "Expert",
+ "yearsOfExperience": 10,
+ "description": "E-commerce platforms, inventory management, supplier systems, and omnichannel retail solutions.",
+ "icon": "ShoppingCart"
+ },
+ {
+ "domain": "Entertainment",
+ "level": "Expert",
+ "yearsOfExperience": 10,
+ "description": "Live show control systems, real-time audio/visual synchronization, and interactive performance technology.",
+ "icon": "Clapperboard"
+ },
+ {
+ "domain": "Theatre",
+ "level": "Expert",
+ "yearsOfExperience": 10,
+ "description": "Stage automation, lighting control systems, MIDI integration, and 3D stereoscopic visual effects for live performances.",
+ "icon": "Drama"
+ },
+ {
+ "domain": "Music Composing",
+ "level": "Advanced",
+ "yearsOfExperience": 15,
+ "description": "Original music composition for performances, electronic music production, and sound design.",
+ "icon": "Music2"
+ }
+]
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/carousel.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/carousel.json
new file mode 100644
index 0000000000000000000000000000000000000000..403d0cf47c8d1d3cead624ab816a1c006cfdafec
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/carousel.json
@@ -0,0 +1,62 @@
+[
+ {
+ "title": "Ark.Alliance",
+ "subtitle": "A New Era for Human Recognition",
+ "description": "Honoring the journey, not just the destination. Your failures today are tomorrow's algorithms. If AI uses OUR collective knowledge to generate BILLIONS in value, we deserve our fair share.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance/Ark_Alliance_Hero.png",
+ "linkUrl": "/projects/ark-alliance",
+ "linkText": "Discover More",
+ "order": 0,
+ "isActive": true
+ },
+ {
+ "title": "Ark.Alliance.StartupCms.AI",
+ "subtitle": "AI-Powered CMS for Startups",
+ "description": "Collaborative profile building with AI assistance, hierarchical team visualization, task tracking with growth-mindset evaluation, and selective public visibility. Built with Next.js 15, Prisma, and multi-provider AI integration.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAiHero.png",
+ "linkUrl": "/projects/ark-alliance-startupcms-ai",
+ "linkText": "View Project",
+ "order": 1,
+ "isActive": true
+ },
+ {
+ "title": "Ark.Alliance.React.Component.UI",
+ "subtitle": "Enterprise React Component Library",
+ "description": "40 component categories spanning Finance, Healthcare, Logistics, and more. React 19, TypeScript 5.9, 258 passing tests with 100% coverage, MVVM architecture.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.React.Component/components-hero.png",
+ "linkUrl": "/projects/ark-alliance-react-component-ui",
+ "linkText": "Explore Components",
+ "order": 2,
+ "isActive": true
+ },
+ {
+ "title": "Ark.Alliance.Trading.Bot",
+ "subtitle": "Automated Cryptocurrency Trading",
+ "description": "Real-time algorithmic trading platform with WebSocket integration, multi-exchange support, and advanced analytics dashboard. Built for high-frequency trading.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.Trading.Bot/bot-hero.png",
+ "linkUrl": "/projects/ark-alliance-trading-bot",
+ "linkText": "Learn More",
+ "order": 3,
+ "isActive": true
+ },
+ {
+ "title": "Ark.Alliance.Trading.Providers.Lib",
+ "subtitle": "Multi-Exchange Trading SDK",
+ "description": "TypeScript SDK unifying cryptocurrency trading across Binance Futures, Deribit with Result pattern, WebSocket streams, and 70+ tested scenarios. Published on NPM.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/providers-hero.png",
+ "linkUrl": "/projects/ark-alliance-trading-providers-lib",
+ "linkText": "View Documentation",
+ "order": 4,
+ "isActive": true
+ },
+ {
+ "title": "Ark.Alliance.Trading.TrendsCalculator",
+ "subtitle": "Real-Time Crypto Trend Analysis",
+ "description": "Production-grade microservice for cryptocurrency trend analysis. Combines Hurst Exponent, GARCH, Linear Regression, and EMA with optional Gemini AI. WebSocket streaming for sub-second updates.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png",
+ "linkUrl": "/projects/ark-alliance-trading-trendscalculator",
+ "linkText": "Explore Trends",
+ "order": 5,
+ "isActive": true
+ }
+]
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/education.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/education.json
new file mode 100644
index 0000000000000000000000000000000000000000..a555e5973341d4a6cd0dbcb161af18d7a9c5526c
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/education.json
@@ -0,0 +1,10 @@
+[
+ {
+ "degree": "Master in Computer Science",
+ "institution": "ULB (Université Libre de Bruxelles)",
+ "fieldOfStudy": "Computer Science - Algorithmic and Software Engineering",
+ "startYear": 1999,
+ "endYear": 2004,
+ "description": "Specialization in Algorithmic and Software Engineering. Comprehensive curriculum covering data structures, algorithms, software design patterns, database systems, and artificial intelligence fundamentals."
+ }
+]
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/experience.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/experience.json
new file mode 100644
index 0000000000000000000000000000000000000000..686327f94dfc7d2ad90bb60efe2cd568a568a6d3
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/experience.json
@@ -0,0 +1,66 @@
+[
+ {
+ "company": "M2H / AI and Technology",
+ "project": "Ark.Alliance Ecosystem; Mindful AI Initiatives",
+ "period": "Dec 2022 - Present",
+ "role": "AI Lead & Principal Solution Architect",
+ "tech": "C#, React, TypeScript, Python, Three.js, Docker, K8s, SLM, OpenAI, Anthropic, Mistral",
+ "desc": "Pioneered mindful AI solutions and the Ark.Alliance Ecosystem. Architected prompt libraries and guidelines for consistent AI experiences. Led full-stack teams (C#, React, Python) in startup environments, implementing resilient patterns (Circuit Breaker, Bulkhead) and robust incident response processes. Built scalable, cloud-native systems from scratch using Agile/DevOps."
+ },
+ {
+ "company": "Ahold Delhaize / Logistics Supply Chain",
+ "project": "New Logistics Systems Design & Optimization",
+ "period": "Jan 2021 - Feb 2025",
+ "role": "Solution & Software Architect",
+ "tech": "C#, .NET 8, Blazor, Microservices, Azure, SAP, CQRS, GitHub, OpenAI API",
+ "desc": "Architected and delivered critical logistics systems (TMS integration, delivery tracking). Led technical analysis and acceptance testing. Designed generic integration tools. Coached cross-functional and offshore teams to ensure high-quality delivery during cutover and HyperCare periods."
+ },
+ {
+ "company": "Candriam / Asset Management",
+ "project": "Asset Position Integration System",
+ "period": "Apr 2020 - Dec 2020",
+ "role": "Software Architect & Full Stack Dev",
+ "tech": "C#, .NET 5, Docker, MQSeries, DB2, Cobol, Microservices, SQL Server, CQRS",
+ "desc": "Reverse-engineered legacy Mainframe systems to modern .NET microservices. Designed and rewrote the asset position integration system (shares, funds) for financial account managers. Executed a seamless migration with zero downtime during cutover."
+ },
+ {
+ "company": "Liberty Steel / Steel Industry",
+ "project": "Web-Based Application Portfolio & SAP Integration",
+ "period": "May 2019 - Apr 2020",
+ "role": "Business Analyst & Full Stack Dev",
+ "tech": "C#, .NET Core, TypeScript, Python, Azure, SAP ERP, Clean Architecture, Blazor",
+ "desc": "Analyzed business flows and developed web-based microservices for steel production logistics. Migrated legacy services to WCF and rewrote production planning schedulers. Integrated deeply with SAP and Mainframe systems using Azure cloud services."
+ },
+ {
+ "company": "Delhaize Group / Retail Logistics",
+ "project": "Logistics Systems Design & Cloud Transformation",
+ "period": "Sep 2011 - Apr 2019",
+ "role": "Full Stack Developer & IT Owner",
+ "tech": "C#, .NET, Entity Framework, Azure, Java, SAP ERP, WMS, IoT, SQL Server/Oracle",
+ "desc": "Owned IT delivery for global logistics reporting and supplier management apps. Modernized legacy systems with SAP and WMS integrations (dock scheduling, EDIFACT). Provided L3 support and implemented ITIL processes for resilient 24/7 logistics operations."
+ },
+ {
+ "company": "Spectacles Charles Kleinberg",
+ "project": "Live Show Control Systems",
+ "period": "Jan 2005 - Nov 2015",
+ "role": "Solution Architect - Developer & Artist",
+ "tech": "C#, Python, C++, DirectX, Unity, Three.js, Max/Msp, Maya, Real-time Systems",
+ "desc": "Architected real-time show control systems synchronizing audio, MIDI, lighting, and 3D Stereoscopic visuals. Developed high-performance interactive solutions in Agile environments. Blended technical engineering with artistic direction for immersive live performances."
+ },
+ {
+ "company": "BNP Paribas Fortis / Banking",
+ "project": "Voice over IP Systems",
+ "period": "Nov 2010 - Feb 2011",
+ "role": "ICT Consultant",
+ "tech": ".NET (C#/VB), SQL Server, SOAP",
+ "desc": "Consulted on the architecture and full-stack development of robust Voice over IP systems for banking infrastructure."
+ },
+ {
+ "company": "Mastercard / Financial Services",
+ "project": "Credit Card Chip Validation",
+ "period": "Nov 2004 - Feb 2005",
+ "role": "Software Engineer",
+ "tech": "C#, C, SQL Server, Assembly",
+ "desc": "Developed critical testing and reporting systems for credit card chip compliance. Collaborated on feature launches to enhance global transaction security."
+ }
+]
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/hobbies.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/hobbies.json
new file mode 100644
index 0000000000000000000000000000000000000000..e13b4ab37f6de8bdd27c61fcb3ceaba47d77fb3f
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/hobbies.json
@@ -0,0 +1,27 @@
+[
+ {
+ "name": "Music Production",
+ "description": "Electronic music composition and production using DAWs, synthesizers, and audio engineering techniques.",
+ "icon": "Headphones"
+ },
+ {
+ "name": "3D Graphics & Animation",
+ "description": "Creating 3D models, animations, and visual effects using Cinema 4D, Maya, and Three.js.",
+ "icon": "Cuboid"
+ },
+ {
+ "name": "Gaming",
+ "description": "Strategy games, simulation, and game development exploration.",
+ "icon": "Gamepad2"
+ },
+ {
+ "name": "Photography",
+ "description": "Digital photography with focus on architectural and landscape subjects.",
+ "icon": "Camera"
+ },
+ {
+ "name": "AI Research",
+ "description": "Exploring cutting-edge AI technologies, prompt engineering, and building AI-powered applications.",
+ "icon": "Brain"
+ }
+]
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/languages.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/languages.json
new file mode 100644
index 0000000000000000000000000000000000000000..1b20b5858612e022b4221038d5ddc149dc7c450e
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/languages.json
@@ -0,0 +1,26 @@
+[
+ {
+ "language": "French",
+ "speaking": 5,
+ "writing": 5,
+ "presenting": 5
+ },
+ {
+ "language": "English",
+ "speaking": 5,
+ "writing": 5,
+ "presenting": 5
+ },
+ {
+ "language": "Spanish",
+ "speaking": 4,
+ "writing": 3,
+ "presenting": 3
+ },
+ {
+ "language": "Dutch",
+ "speaking": 2,
+ "writing": 1,
+ "presenting": 1
+ }
+]
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/profile.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/profile.json
new file mode 100644
index 0000000000000000000000000000000000000000..689b356a3788c9cd24d8789bd699ec80ae7ca14e
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/profile.json
@@ -0,0 +1,10 @@
+{
+ "firstName": "Armand",
+ "lastName": "Richelet-Kleinberg",
+ "title": "AI Principal Solutions Architect - Full Stack Dev - Business & Technical Analyst",
+ "overview": "Experienced AI Principal Architect with 20+ years in software development and system architecture, focused on the AI industry. Specialized in designing and delivering AI-driven solutions, MLOps pipelines, and cloud-native systems using C#, TypeScript (React), Js, Python. Proven ability to build scalable, event-driven architectures and integrate advanced AI frameworks. Expert in Agile/DevOps environments, translating complex AI business needs into robust, production-grade platforms.",
+ "email": "arkleinberg@gmail.com",
+ "githubUrl": "https://github.com/ArmandRicheletKleinberg",
+ "linkedinUrl": "https://do.linkedin.com/in/arkleinberg/es",
+ "avatarUrl": "/Assets/Site/Icon.png"
+}
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/projects.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/projects.json
new file mode 100644
index 0000000000000000000000000000000000000000..6b901996518c50e34399f34fd7c3910b71a3322e
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/projects.json
@@ -0,0 +1,169 @@
+[
+ {
+ "title": "Ark.Alliance Trading Ecosystem",
+ "description": "A high-frequency crypto trading bot and ecosystem featuring a cyberpunk dashboard, real-time WebSocket streaming, and AI-driven trend detection. Built on a microservices architecture with a focus on resilience and speed.",
+ "status": "In Progress",
+ "isFeatured": true,
+ "technologies": [
+ "C#",
+ "React",
+ "TypeScript",
+ "Python",
+ "Docker",
+ "Kubernetes",
+ "Three.js",
+ "OpenAI"
+ ],
+ "imageUrl": "/assets/Bot10.PNG",
+ "repoUrl": "https://github.com/ark/alliance",
+ "demoUrl": "https://ark-alliance.demo",
+ "startDate": "2022-12-01",
+ "features": [
+ {
+ "title": "Strategy Command Center",
+ "description": "The central nerve center of the operation. Visualizes PnL in real-time with sub-millisecond updates via WebSockets. The 'Cyberpunk' aesthetic isn't just for show—it uses high-contrast neon elements to make critical alerts visible instantly.",
+ "icon": "monitor",
+ "imageUrl": "/assets/Bot10.PNG"
+ },
+ {
+ "title": "3D Market Topography",
+ "description": "Interactive Three.js visualization of the order book. Peaks and valleys represent buy/sell walls. This allows the trader to 'Surf the Wave' by visually identifying support and resistance zones in 3D space.",
+ "icon": "box",
+ "imageUrl": "/assets/Bot6.PNG"
+ },
+ {
+ "title": "AI Logic Analysis",
+ "description": "Real-time introspection into the 'Gemini' AI Strategy. Shows the calculated 'Sigma' (volatility threshold) and 'Trend Confidence' score. This is where the 'Wait' vs 'Trade' decisions happen.",
+ "icon": "cpu",
+ "imageUrl": "/assets/Bot2.PNG"
+ },
+ {
+ "title": "Logistics Matrix",
+ "description": "A grid view for managing hundreds of concurrent 'Worker' instances. Each cell represents a Docker container running a specific strategy on a specific pair. Green = Profit, Red = Inversion/Loss.",
+ "icon": "grid",
+ "imageUrl": "/assets/Bot13.PNG"
+ },
+ {
+ "title": "Configuration Console",
+ "description": "Fine-grained control over the 'Click' parameters. Here you set the 'Take Profit Step' (e.g., 0.05%) and the 'Inversion Sigma'. Changes propagate to active instances immediately.",
+ "icon": "sliders",
+ "imageUrl": "/assets/Bot5.PNG"
+ },
+ {
+ "title": "Execution Logs",
+ "description": "Live stream of order execution events. Tracks latency statistics (e.g., 'Order to Ack: 45ms') and API weight usage to prevent bans.",
+ "icon": "activity",
+ "imageUrl": "/assets/Bot4.PNG"
+ }
+ ],
+ "pages": [
+ {
+ "type": "OVERVIEW",
+ "title": "Surfing on the Wave",
+ "content": "### Philosophy: Chaos as Potential\n\nThe **Ark.Alliance** strategy is built on a simple premise: *You cannot predict the ocean, but you can learn to surf.* \n\nInstead of trying to forecast price 10 minutes from now, the bot reacts to *micro-movements* in the present moment. We call this **'Click Strategy'**.\n\n#### The 'Click' Mechanism\n\n1. **Entry (The Paddle)**: The bot enters a position based on **Gemini AI Analysis** of order book imbalance and volatility.\n2. **Surfing (The Ride)**: As price moves in favor, the bot executes 'Clicks'—partial take-profits at fixed intervals (e.g., every +0.1% PnL).\n * **Ratchet Effect**: Each click raises the 'Inversion Threshold' (Stop Loss), locking in gains.\n3. **Inversion (The Bail)**: If the wave breaks (price reverses), the bot hits the 'Inversion Threshold'.\n * It instantly closes the position and flips to the opposite side (2x quantity).\n * **Result**: The surfer catches the *new* wave immediately.\n\n```mermaid\nstateDiagram-v2\n [*] --> Entry\n Entry --> Surfing: Price Moves Up\n Surfing --> Click: +0.1% Gain\n Click --> Surfing: Raise Safety Net\n Surfing --> Inversion: Hit Safety Net\n Inversion --> [*]: Flip Position\n```"
+ },
+ {
+ "type": "TECHNICAL",
+ "title": "Engineering Resilience",
+ "content": "### Speed vs. Reliability\n\nCrypto markets are 24/7 and unforgiving. The bot's architecture prioritizes **Resilience** over raw speed, though it achieves both.\n\n#### 1. Hybrid Push/Pull Architecture\n\nReliance on WebSockets alone is dangerous (silent disconnects). Reliability on Polling alone is too slow. We use **Both**.\n\n* **Fast Path (Push)**: `BinanceUserDataStream` delivers order updates in ~50ms.\n* **Safe Path (Pull)**: A `MonitoringLayout` polls the API every 200ms. If the WebSocket misses an event, the Poller catches it.\n\n#### 2. Fee Management & Pre-Computation\n\nTrading frequently ('Clicking') accumulates fees. Ignorance of fees leads to 'Death by a Thousand Cuts'.\n\n* **Maker vs Taker**: The bot prefers `POST_ONLY` (Maker) orders to gain rebates.\n* **Pre-Computation**: Before placing *any* trade, the `FuturesCost Service` calculates:\n * `OpenFee` + `CloseFee` + `FundingCost`\n * **Rule**: The first 'Click' target is moved *further out* to cover these costs. You are never 'Green' until the fees are paid.\n\n#### 3. Rate Limit Arbitrage\n\nBinance allows 1200 weight/minute. \n* The **RateLimiter** service tracks usage in real-time.\n* If usage > 80%, it switches non-critical polls to 'Lazy Mode', saving bandwidth for critical 'Inversion' orders.\n\n```mermaid\nsequenceDiagram\n participant Bot\n participant RateLimiter\n participant Binance\n\n Bot->>RateLimiter: Can I Order?\n RateLimiter->>RateLimiter: Check Weight (1100/1200)\n alt Critical (Inversion)\n RateLimiter-->>Bot: YES (Emergency Override)\n else Standard (Poll)\n RateLimiter-->>Bot: PAUSE (Save for Trade)\n end\n Bot->>Binance: Execute Order\n```"
+ },
+ {
+ "type": "FUNCTIONAL",
+ "title": "Functional Gallery",
+ "content": "Experience the interface designed for the high-stakes environment of algorithmic trading."
+ }
+ ]
+ },
+ {
+ "title": "Logistics Orchestration Platform",
+ "description": "A comprehensive logistics supply chain platform for Ahold Delhaize, integrating TMS (Transport Management Systems), SAP, and real-time delivery tracking.",
+ "status": "Completed",
+ "isFeatured": true,
+ "technologies": [
+ "C#",
+ ".NET 8",
+ "Blazor",
+ "Azure",
+ "SAP",
+ "Microservices",
+ "CQRS"
+ ],
+ "imageUrl": "/assets/Bot13.PNG",
+ "startDate": "2021-01-01",
+ "endDate": "2025-02-01",
+ "features": [
+ {
+ "title": "TMS Integration",
+ "description": "Seamless connecting with Ortec & Axiodis TMS.",
+ "icon": "truck"
+ },
+ {
+ "title": "Global Tracking",
+ "description": "Real-time visibility into delivery status across Europe.",
+ "icon": "map"
+ }
+ ],
+ "pages": [
+ {
+ "type": "OVERVIEW",
+ "title": "Strategic Impact",
+ "content": "Revitalized logistics core by moving to Domain-Driven Design microservices, achieving 30% cost reduction."
+ }
+ ]
+ },
+ {
+ "title": "Live Show Control System",
+ "description": "Real-time audiovisual synchronization system for immersive live performances.",
+ "status": "Completed",
+ "technologies": [
+ "C++",
+ "Python",
+ "Unity",
+ "C#"
+ ],
+ "imageUrl": "/assets/Bot6.PNG",
+ "startDate": "2005-01-01",
+ "endDate": "2015-11-01",
+ "features": [
+ {
+ "title": "AV Sync",
+ "description": "Frame-perfect synchronization.",
+ "icon": "music"
+ },
+ {
+ "title": "3D Visuals",
+ "description": "Real-time stereoscopic 3D content.",
+ "icon": "box"
+ }
+ ],
+ "pages": [
+ {
+ "type": "OVERVIEW",
+ "title": "Art Meets Engineering",
+ "content": "Bridging technical precision and artistic expression for major live spectacles."
+ }
+ ]
+ },
+ {
+ "title": "Asset Position Integration",
+ "description": "Financial system integration bridging legacy Mainframe data with modern web interfaces.",
+ "status": "Completed",
+ "technologies": [
+ "C#",
+ ".NET 5",
+ "Docker",
+ "MQSeries",
+ "Cobol"
+ ],
+ "imageUrl": "/assets/Bot12.PNG",
+ "startDate": "2020-04-01",
+ "endDate": "2020-12-01",
+ "features": [
+ {
+ "title": "Legacy Bridge",
+ "description": "Secure communication with Mainframe.",
+ "icon": "server"
+ }
+ ]
+ }
+]
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/skills.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/skills.json
new file mode 100644
index 0000000000000000000000000000000000000000..1c5f85fd3ab6923708216f618b7e79185eddef15
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/skills.json
@@ -0,0 +1,49 @@
+{
+ "languages": [
+ "C#",
+ "Python",
+ "Java",
+ "TypeScript",
+ "JavaScript",
+ "C",
+ "C++",
+ "T-SQL",
+ "PL-SQL"
+ ],
+ "frameworks": [
+ ".NET up to 10",
+ "Entity Framework",
+ "Python Ecosystem",
+ "Unity",
+ "Adobe Suite",
+ "Cinema 4D"
+ ],
+ "databases": [
+ "SQL Server",
+ "SQLite",
+ "PostgreSQL",
+ "MongoDB",
+ "DB2",
+ "Oracle 9i",
+ "Sybase"
+ ],
+ "tools": [
+ "Docker",
+ "Kubernetes",
+ "Azure Services",
+ "GitHub",
+ "PyTorch",
+ "RabbitMQ",
+ "AWS Services",
+ "Unreal/Three.js"
+ ],
+ "methodologies": [
+ "DDD",
+ "CQRS",
+ "Event-Driven Architecture",
+ "Microservices",
+ "MLOps",
+ "Agile/Scrum",
+ "DevOps"
+ ]
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/technologies.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/technologies.json
new file mode 100644
index 0000000000000000000000000000000000000000..f3216137a337352c1a75d5e64c63171fa2c92c7c
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/technologies.json
@@ -0,0 +1,1285 @@
+{
+ "categories": [
+ {
+ "id": "frontend",
+ "name": "Frontend Frameworks & Libraries",
+ "description": "Client-side web development technologies",
+ "order": 1
+ },
+ {
+ "id": "languages",
+ "name": "Programming Languages",
+ "description": "Core programming languages",
+ "order": 2
+ },
+ {
+ "id": "runtimes",
+ "name": "Runtimes & Platforms",
+ "description": "Runtime environments and development platforms",
+ "order": 3
+ },
+ {
+ "id": "backend",
+ "name": "Backend Frameworks",
+ "description": "Server-side frameworks and libraries",
+ "order": 4
+ },
+ {
+ "id": "databases",
+ "name": "Databases",
+ "description": "Relational and NoSQL database systems",
+ "order": 5
+ },
+ {
+ "id": "cloud",
+ "name": "Cloud Platforms",
+ "description": "Cloud computing providers and services",
+ "order": 6
+ },
+ {
+ "id": "devops",
+ "name": "DevOps & Infrastructure",
+ "description": "CI/CD, containerization, and infrastructure tools",
+ "order": 7
+ },
+ {
+ "id": "messaging",
+ "name": "Message Brokers & Queues",
+ "description": "Event streaming and message queue systems",
+ "order": 8
+ },
+ {
+ "id": "ai",
+ "name": "AI/ML & Data Science",
+ "description": "Artificial intelligence and machine learning technologies",
+ "order": 9
+ },
+ {
+ "id": "enterprise",
+ "name": "Enterprise Systems",
+ "description": "ERP, CRM, and enterprise software platforms",
+ "order": 10
+ },
+ {
+ "id": "patterns",
+ "name": "Architecture Patterns",
+ "description": "Architectural patterns and API specifications",
+ "order": 11
+ },
+ {
+ "id": "apis",
+ "name": "External APIs & Services",
+ "description": "Third-party APIs and integration services",
+ "order": 12
+ },
+ {
+ "id": "testing",
+ "name": "Testing & Quality",
+ "description": "Testing frameworks and quality assurance tools",
+ "order": 13
+ },
+ {
+ "id": "mobile",
+ "name": "Mobile Development",
+ "description": "Mobile app development frameworks",
+ "order": 14
+ },
+ {
+ "id": "styling",
+ "name": "Styling & Design",
+ "description": "CSS frameworks and design tools",
+ "order": 15
+ },
+ {
+ "id": "blockchain-platform",
+ "name": "Blockchain Platforms",
+ "description": "Layer-1 and layer-2 blockchain networks",
+ "order": 16
+ },
+ {
+ "id": "distributed-ledger",
+ "name": "Distributed Ledger Technology",
+ "description": "Blockchain and decentralized technologies",
+ "order": 17
+ },
+ {
+ "id": "consensus-mechanism",
+ "name": "Consensus Mechanisms",
+ "description": "Blockchain consensus algorithms",
+ "order": 18
+ },
+ {
+ "id": "blockchain-standard",
+ "name": "Blockchain Standards",
+ "description": "Token standards and blockchain protocols",
+ "order": 19
+ },
+ {
+ "id": "mining-platform",
+ "name": "Mining Platforms",
+ "description": "Cryptocurrency mining operating systems",
+ "order": 20
+ },
+ {
+ "id": "mining-hardware",
+ "name": "Mining Hardware",
+ "description": "ASIC and GPU mining equipment",
+ "order": 21
+ },
+ {
+ "id": "blockchain-layer2",
+ "name": "Layer-2 Solutions",
+ "description": "Scaling solutions for blockchain networks",
+ "order": 22
+ },
+ {
+ "id": "leadership",
+ "name": "Leadership & Management",
+ "description": "Team management and leadership skills",
+ "order": 23
+ },
+ {
+ "id": "markup-language",
+ "name": "Markup Languages",
+ "description": "HTML and other markup technologies",
+ "order": 24
+ },
+ {
+ "id": "styling-language",
+ "name": "Styling Languages",
+ "description": "CSS and styling technologies",
+ "order": 25
+ },
+ {
+ "id": "css-preprocessor",
+ "name": "CSS Preprocessors",
+ "description": "SASS, LESS, and other CSS preprocessors",
+ "order": 26
+ },
+ {
+ "id": "data-format",
+ "name": "Data Formats",
+ "description": "JSON, XML, and other data interchange formats",
+ "order": 27
+ },
+ {
+ "id": "crypto-exchange-api",
+ "name": "Crypto Exchange APIs",
+ "description": "Cryptocurrency exchange trading APIs",
+ "order": 28
+ },
+ {
+ "id": "cybersecurity",
+ "name": "Cybersecurity",
+ "description": "Security testing and ethical hacking",
+ "order": 29
+ }
+ ],
+ "technologies": [
+ {
+ "key": "react",
+ "name": "React",
+ "label": "React.js",
+ "category": "frontend",
+ "description": "A JavaScript library for building user interfaces with component-based architecture",
+ "icon": "fab fa-react",
+ "color": "#61DAFB",
+ "website": "https://react.dev",
+ "versions": [
+ "16",
+ "17",
+ "18",
+ "19"
+ ]
+ },
+ {
+ "key": "angular",
+ "name": "Angular",
+ "label": "Angular",
+ "category": "frontend",
+ "description": "A TypeScript-based web application framework led by Google",
+ "icon": "fab fa-angular",
+ "color": "#DD0031",
+ "website": "https://angular.io"
+ },
+ {
+ "key": "vue",
+ "name": "Vue.js",
+ "label": "Vue.js",
+ "category": "frontend",
+ "description": "A progressive JavaScript framework for building user interfaces",
+ "icon": "fab fa-vuejs",
+ "color": "#4FC08D",
+ "website": "https://vuejs.org"
+ },
+ {
+ "key": "svelte",
+ "name": "Svelte",
+ "label": "Svelte",
+ "category": "frontend",
+ "description": "A compiler-based framework that shifts work from runtime to build time",
+ "icon": "devicon-svelte-plain",
+ "color": "#FF3E00",
+ "website": "https://svelte.dev"
+ },
+ {
+ "key": "nextjs",
+ "name": "Next.js",
+ "label": "Next.js",
+ "category": "frontend",
+ "description": "A React framework for production with hybrid static & server rendering",
+ "icon": "devicon-nextjs-original",
+ "color": "#000000",
+ "website": "https://nextjs.org"
+ },
+ {
+ "key": "blazor",
+ "name": "Blazor",
+ "label": "Blazor",
+ "category": "frontend",
+ "description": "A framework for building interactive web UIs using C# instead of JavaScript",
+ "icon": "devicon-dotnetcore-plain",
+ "color": "#512BD4",
+ "website": "https://dotnet.microsoft.com/apps/aspnet/web-apps/blazor"
+ },
+ {
+ "key": "threejs",
+ "name": "Three.js",
+ "label": "Three.js",
+ "category": "frontend",
+ "description": "A cross-browser JavaScript library for creating 3D graphics in web browsers",
+ "icon": "devicon-threejs-original",
+ "color": "#000000",
+ "website": "https://threejs.org"
+ },
+ {
+ "key": "typescript",
+ "name": "TypeScript",
+ "label": "TypeScript",
+ "category": "languages",
+ "description": "A strongly typed programming language that builds on JavaScript",
+ "icon": "devicon-typescript-plain",
+ "color": "#3178C6",
+ "website": "https://www.typescriptlang.org"
+ },
+ {
+ "key": "javascript",
+ "name": "JavaScript",
+ "label": "JavaScript",
+ "category": "languages",
+ "description": "A dynamic programming language that powers the web",
+ "icon": "fab fa-js-square",
+ "color": "#F7DF1E",
+ "website": "https://developer.mozilla.org/en-US/docs/Web/JavaScript"
+ },
+ {
+ "key": "csharp",
+ "name": "C#",
+ "label": "C#",
+ "category": "languages",
+ "description": "A modern, object-oriented programming language developed by Microsoft",
+ "icon": "devicon-csharp-plain",
+ "color": "#239120",
+ "website": "https://docs.microsoft.com/en-us/dotnet/csharp/"
+ },
+ {
+ "key": "cpp",
+ "name": "C++",
+ "label": "C++",
+ "category": "languages",
+ "description": "A high-performance programming language for systems and applications",
+ "icon": "devicon-cplusplus-plain",
+ "color": "#00599C",
+ "website": "https://isocpp.org"
+ },
+ {
+ "key": "java",
+ "name": "Java",
+ "label": "Java",
+ "category": "languages",
+ "description": "A class-based, object-oriented programming language for enterprise applications",
+ "icon": "fab fa-java",
+ "color": "#007396",
+ "website": "https://www.java.com"
+ },
+ {
+ "key": "go",
+ "name": "Go",
+ "label": "Go (Golang)",
+ "category": "languages",
+ "description": "A statically typed, compiled language designed at Google for simplicity and efficiency",
+ "icon": "devicon-go-original-wordmark",
+ "color": "#00ADD8",
+ "website": "https://go.dev"
+ },
+ {
+ "key": "rust",
+ "name": "Rust",
+ "label": "Rust",
+ "category": "languages",
+ "description": "A systems programming language focused on safety, speed, and concurrency",
+ "icon": "devicon-rust-plain",
+ "color": "#DEA584",
+ "website": "https://www.rust-lang.org"
+ },
+ {
+ "key": "cobol",
+ "name": "Cobol",
+ "label": "COBOL",
+ "category": "languages",
+ "description": "A business-oriented programming language used in mainframe systems",
+ "icon": "fas fa-code",
+ "color": "#005CA5",
+ "website": "https://www.ibm.com/products/cobol-compiler-zos"
+ },
+ {
+ "key": "nodejs",
+ "name": "Node.js",
+ "label": "Node.js",
+ "category": "runtimes",
+ "description": "A JavaScript runtime built on Chrome's V8 engine for server-side development",
+ "icon": "fab fa-node-js",
+ "color": "#339933",
+ "website": "https://nodejs.org"
+ },
+ {
+ "key": "dotnet",
+ "name": ".NET",
+ "label": ".NET",
+ "category": "runtimes",
+ "description": "A free, cross-platform, open-source developer platform by Microsoft",
+ "icon": "devicon-dotnetcore-plain",
+ "color": "#512BD4",
+ "website": "https://dotnet.microsoft.com",
+ "versions": [
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10"
+ ]
+ },
+ {
+ "key": "unity",
+ "name": "Unity",
+ "label": "Unity Engine",
+ "category": "runtimes",
+ "description": "A cross-platform game engine for 2D/3D games and interactive experiences",
+ "icon": "devicon-unity-original",
+ "color": "#000000",
+ "website": "https://unity.com"
+ },
+ {
+ "key": "unreal",
+ "name": "Unreal Engine",
+ "label": "Unreal Engine",
+ "category": "runtimes",
+ "description": "A powerful 3D game engine for AAA game development and visualization",
+ "icon": "devicon-unrealengine-original",
+ "color": "#0E1128",
+ "website": "https://www.unrealengine.com"
+ },
+ {
+ "key": "express",
+ "name": "Express.js",
+ "label": "Express.js",
+ "category": "backend",
+ "description": "A fast, unopinionated, minimalist web framework for Node.js",
+ "icon": "devicon-express-original",
+ "color": "#000000",
+ "website": "https://expressjs.com"
+ },
+ {
+ "key": "nestjs",
+ "name": "NestJS",
+ "label": "NestJS",
+ "category": "backend",
+ "description": "A progressive Node.js framework for building efficient server-side applications",
+ "icon": "devicon-nestjs-plain",
+ "color": "#E0234E",
+ "website": "https://nestjs.com"
+ },
+ {
+ "key": "fastapi",
+ "name": "FastAPI",
+ "label": "FastAPI",
+ "category": "backend",
+ "description": "A modern, fast Python web framework for building APIs with automatic OpenAPI docs",
+ "icon": "devicon-fastapi-plain",
+ "color": "#009688",
+ "website": "https://fastapi.tiangolo.com"
+ },
+ {
+ "key": "django",
+ "name": "Django",
+ "label": "Django",
+ "category": "backend",
+ "description": "A high-level Python web framework for rapid development",
+ "icon": "devicon-django-plain",
+ "color": "#092E20",
+ "website": "https://www.djangoproject.com"
+ },
+ {
+ "key": "flask",
+ "name": "Flask",
+ "label": "Flask",
+ "category": "backend",
+ "description": "A lightweight WSGI web application framework in Python",
+ "icon": "devicon-flask-original",
+ "color": "#000000",
+ "website": "https://flask.palletsprojects.com"
+ },
+ {
+ "key": "aspnetcore",
+ "name": "ASP.NET Core",
+ "label": "ASP.NET Core",
+ "category": "backend",
+ "description": "A cross-platform, high-performance framework for building modern web apps",
+ "icon": "devicon-dotnetcore-plain",
+ "color": "#512BD4",
+ "website": "https://docs.microsoft.com/en-us/aspnet/core"
+ },
+ {
+ "key": "spring",
+ "name": "Spring",
+ "label": "Spring Boot",
+ "category": "backend",
+ "description": "A Java-based framework for building enterprise-grade applications",
+ "icon": "devicon-spring-plain",
+ "color": "#6DB33F",
+ "website": "https://spring.io"
+ },
+ {
+ "key": "sqlite",
+ "name": "SQLite",
+ "label": "SQLite",
+ "category": "databases",
+ "description": "A lightweight, serverless, self-contained SQL database engine",
+ "icon": "devicon-sqlite-plain",
+ "color": "#003B57",
+ "website": "https://www.sqlite.org"
+ },
+ {
+ "key": "postgresql",
+ "name": "PostgreSQL",
+ "label": "PostgreSQL",
+ "category": "databases",
+ "description": "A powerful, open-source object-relational database system",
+ "icon": "devicon-postgresql-plain",
+ "color": "#4169E1",
+ "website": "https://www.postgresql.org"
+ },
+ {
+ "key": "mysql",
+ "name": "MySQL",
+ "label": "MySQL",
+ "category": "databases",
+ "description": "The world's most popular open-source relational database",
+ "icon": "devicon-mysql-plain",
+ "color": "#4479A1",
+ "website": "https://www.mysql.com"
+ },
+ {
+ "key": "sqlserver",
+ "name": "SQL Server",
+ "label": "SQL Server",
+ "category": "databases",
+ "description": "Microsoft's enterprise-grade relational database management system",
+ "icon": "devicon-microsoftsqlserver-plain",
+ "color": "#CC2927",
+ "website": "https://www.microsoft.com/sql-server"
+ },
+ {
+ "key": "mongodb",
+ "name": "MongoDB",
+ "label": "MongoDB",
+ "category": "databases",
+ "description": "A document-based NoSQL database for modern applications",
+ "icon": "devicon-mongodb-plain",
+ "color": "#47A248",
+ "website": "https://www.mongodb.com"
+ },
+ {
+ "key": "redis",
+ "name": "Redis",
+ "label": "Redis",
+ "category": "databases",
+ "description": "An in-memory data structure store used as database, cache, and message broker",
+ "icon": "devicon-redis-plain",
+ "color": "#DC382D",
+ "website": "https://redis.io"
+ },
+ {
+ "key": "elasticsearch",
+ "name": "Elasticsearch",
+ "label": "Elasticsearch",
+ "category": "databases",
+ "description": "A distributed search and analytics engine for all types of data",
+ "icon": "devicon-elasticsearch-original",
+ "color": "#005571",
+ "website": "https://www.elastic.co"
+ },
+ {
+ "key": "oracle",
+ "name": "Oracle",
+ "label": "Oracle Database",
+ "category": "databases",
+ "description": "A multi-model database management system for enterprise workloads",
+ "icon": "devicon-oracle-original",
+ "color": "#F80000",
+ "website": "https://www.oracle.com/database"
+ },
+ {
+ "key": "db2",
+ "name": "DB2",
+ "label": "IBM DB2",
+ "category": "databases",
+ "description": "IBM's family of data management products including database servers",
+ "icon": "fas fa-database",
+ "color": "#052FAD",
+ "website": "https://www.ibm.com/products/db2"
+ },
+ {
+ "key": "aws",
+ "name": "AWS",
+ "label": "Amazon Web Services",
+ "category": "cloud",
+ "description": "The world's leading cloud computing platform by Amazon",
+ "icon": "fab fa-aws",
+ "color": "#FF9900",
+ "website": "https://aws.amazon.com"
+ },
+ {
+ "key": "azure",
+ "name": "Azure",
+ "label": "Microsoft Azure",
+ "category": "cloud",
+ "description": "Microsoft's cloud computing platform for building, testing, and managing applications",
+ "icon": "devicon-azure-plain",
+ "color": "#0078D4",
+ "website": "https://azure.microsoft.com"
+ },
+ {
+ "key": "gcp",
+ "name": "Google Cloud",
+ "label": "Google Cloud Platform",
+ "category": "cloud",
+ "description": "Google's suite of cloud computing services",
+ "icon": "devicon-googlecloud-plain",
+ "color": "#4285F4",
+ "website": "https://cloud.google.com"
+ },
+ {
+ "key": "digitalocean",
+ "name": "DigitalOcean",
+ "label": "DigitalOcean",
+ "category": "cloud",
+ "description": "A cloud infrastructure provider focused on simplicity for developers",
+ "icon": "devicon-digitalocean-plain",
+ "color": "#0080FF",
+ "website": "https://www.digitalocean.com"
+ },
+ {
+ "key": "vercel",
+ "name": "Vercel",
+ "label": "Vercel",
+ "category": "cloud",
+ "description": "A cloud platform for static sites and serverless functions",
+ "icon": "devicon-vercel-original",
+ "color": "#000000",
+ "website": "https://vercel.com"
+ },
+ {
+ "key": "docker",
+ "name": "Docker",
+ "label": "Docker",
+ "category": "devops",
+ "description": "A platform for developing, shipping, and running applications in containers",
+ "icon": "fab fa-docker",
+ "color": "#2496ED",
+ "website": "https://www.docker.com"
+ },
+ {
+ "key": "kubernetes",
+ "name": "Kubernetes",
+ "label": "Kubernetes (K8s)",
+ "category": "devops",
+ "description": "An open-source system for automating deployment and management of containerized applications",
+ "icon": "devicon-kubernetes-plain",
+ "color": "#326CE5",
+ "website": "https://kubernetes.io"
+ },
+ {
+ "key": "terraform",
+ "name": "Terraform",
+ "label": "Terraform",
+ "category": "devops",
+ "description": "An infrastructure as code tool for building, changing, and versioning infrastructure",
+ "icon": "devicon-terraform-plain",
+ "color": "#7B42BC",
+ "website": "https://www.terraform.io"
+ },
+ {
+ "key": "github-actions",
+ "name": "GitHub Actions",
+ "label": "GitHub Actions",
+ "category": "devops",
+ "description": "CI/CD platform integrated with GitHub for automating workflows",
+ "icon": "fab fa-github",
+ "color": "#2088FF",
+ "website": "https://github.com/features/actions"
+ },
+ {
+ "key": "jenkins",
+ "name": "Jenkins",
+ "label": "Jenkins",
+ "category": "devops",
+ "description": "An open-source automation server for building, deploying, and automating projects",
+ "icon": "devicon-jenkins-line",
+ "color": "#D24939",
+ "website": "https://www.jenkins.io"
+ },
+ {
+ "key": "gitlab-ci",
+ "name": "GitLab CI",
+ "label": "GitLab CI/CD",
+ "category": "devops",
+ "description": "GitLab's built-in continuous integration and deployment tool",
+ "icon": "fab fa-gitlab",
+ "color": "#FC6D26",
+ "website": "https://docs.gitlab.com/ee/ci"
+ },
+ {
+ "key": "ansible",
+ "name": "Ansible",
+ "label": "Ansible",
+ "category": "devops",
+ "description": "An open-source automation tool for configuration management and deployment",
+ "icon": "devicon-ansible-plain",
+ "color": "#EE0000",
+ "website": "https://www.ansible.com"
+ },
+ {
+ "key": "nginx",
+ "name": "NGINX",
+ "label": "NGINX",
+ "category": "devops",
+ "description": "A high-performance web server, reverse proxy, and load balancer",
+ "icon": "devicon-nginx-original",
+ "color": "#009639",
+ "website": "https://nginx.org"
+ },
+ {
+ "key": "rabbitmq",
+ "name": "RabbitMQ",
+ "label": "RabbitMQ",
+ "category": "messaging",
+ "description": "An open-source message broker implementing AMQP protocol",
+ "icon": "devicon-rabbitmq-original",
+ "color": "#FF6600",
+ "website": "https://www.rabbitmq.com"
+ },
+ {
+ "key": "kafka",
+ "name": "Kafka",
+ "label": "Apache Kafka",
+ "category": "messaging",
+ "description": "A distributed event streaming platform for high-throughput data pipelines",
+ "icon": "devicon-apachekafka-original",
+ "color": "#231F20",
+ "website": "https://kafka.apache.org"
+ },
+ {
+ "key": "mqseries",
+ "name": "MQSeries",
+ "label": "IBM MQ",
+ "category": "messaging",
+ "description": "IBM's enterprise message-oriented middleware for reliable messaging",
+ "icon": "fas fa-exchange-alt",
+ "color": "#052FAD",
+ "website": "https://www.ibm.com/products/mq"
+ },
+ {
+ "key": "azure-service-bus",
+ "name": "Azure Service Bus",
+ "label": "Azure Service Bus",
+ "category": "messaging",
+ "description": "A fully managed enterprise message broker with message queues and publish-subscribe topics",
+ "icon": "devicon-azure-plain",
+ "color": "#0078D4",
+ "website": "https://azure.microsoft.com/services/service-bus"
+ },
+ {
+ "key": "pytorch",
+ "name": "PyTorch",
+ "label": "PyTorch",
+ "category": "ai",
+ "description": "An open-source machine learning framework based on the Torch library",
+ "icon": "devicon-pytorch-original",
+ "color": "#EE4C2C",
+ "website": "https://pytorch.org"
+ },
+ {
+ "key": "tensorflow",
+ "name": "TensorFlow",
+ "label": "TensorFlow",
+ "category": "ai",
+ "description": "An end-to-end open-source platform for machine learning",
+ "icon": "devicon-tensorflow-original",
+ "color": "#FF6F00",
+ "website": "https://www.tensorflow.org"
+ },
+ {
+ "key": "openai",
+ "name": "OpenAI",
+ "label": "OpenAI API",
+ "category": "ai",
+ "description": "AI models and APIs including GPT-4, DALL-E, and Whisper",
+ "icon": "fas fa-robot",
+ "color": "#412991",
+ "website": "https://openai.com"
+ },
+ {
+ "key": "anthropic",
+ "name": "Anthropic",
+ "label": "Claude API",
+ "category": "ai",
+ "description": "Anthropic's Claude AI assistant and API for safe, helpful AI",
+ "icon": "fas fa-brain",
+ "color": "#CC9B7A",
+ "website": "https://www.anthropic.com"
+ },
+ {
+ "key": "gemini",
+ "name": "Gemini",
+ "label": "Google Gemini",
+ "category": "ai",
+ "description": "Google's multimodal AI model for text, images, and code",
+ "icon": "fas fa-gem",
+ "color": "#4285F4",
+ "website": "https://deepmind.google/technologies/gemini"
+ },
+ {
+ "key": "huggingface",
+ "name": "Hugging Face",
+ "label": "Hugging Face",
+ "category": "ai",
+ "description": "The AI community platform with models, datasets, and ML applications",
+ "icon": "fas fa-smile",
+ "color": "#FFD21E",
+ "website": "https://huggingface.co"
+ },
+ {
+ "key": "langchain",
+ "name": "LangChain",
+ "label": "LangChain",
+ "category": "ai",
+ "description": "A framework for developing applications powered by language models",
+ "icon": "fas fa-link",
+ "color": "#1C3C3C",
+ "website": "https://www.langchain.com"
+ },
+ {
+ "key": "pandas",
+ "name": "Pandas",
+ "label": "Pandas",
+ "category": "ai",
+ "description": "A fast, powerful data analysis and manipulation library for Python",
+ "icon": "devicon-pandas-original",
+ "color": "#150458",
+ "website": "https://pandas.pydata.org"
+ },
+ {
+ "key": "numpy",
+ "name": "NumPy",
+ "label": "NumPy",
+ "category": "ai",
+ "description": "The fundamental package for scientific computing with Python",
+ "icon": "devicon-numpy-original",
+ "color": "#013243",
+ "website": "https://numpy.org"
+ },
+ {
+ "key": "sap",
+ "name": "SAP",
+ "label": "SAP ERP",
+ "category": "enterprise",
+ "description": "Enterprise resource planning software for business operations",
+ "icon": "fas fa-building",
+ "color": "#0FAAFF",
+ "website": "https://www.sap.com"
+ },
+ {
+ "key": "salesforce",
+ "name": "Salesforce",
+ "label": "Salesforce",
+ "category": "enterprise",
+ "description": "The world's leading customer relationship management (CRM) platform",
+ "icon": "devicon-salesforce-plain",
+ "color": "#00A1E0",
+ "website": "https://www.salesforce.com"
+ },
+ {
+ "key": "dynamics365",
+ "name": "Dynamics 365",
+ "label": "Microsoft Dynamics 365",
+ "category": "enterprise",
+ "description": "Microsoft's portfolio of enterprise resource planning and CRM applications",
+ "icon": "fab fa-microsoft",
+ "color": "#002050",
+ "website": "https://dynamics.microsoft.com"
+ },
+ {
+ "key": "microservices",
+ "name": "Microservices",
+ "label": "Microservices Architecture",
+ "category": "patterns",
+ "description": "An architectural style that structures an application as loosely coupled services",
+ "icon": "fas fa-cubes",
+ "color": "#6C5CE7"
+ },
+ {
+ "key": "cqrs",
+ "name": "CQRS",
+ "label": "CQRS",
+ "category": "patterns",
+ "description": "Command Query Responsibility Segregation - separating read and write operations",
+ "icon": "fas fa-exchange-alt",
+ "color": "#00B894"
+ },
+ {
+ "key": "event-sourcing",
+ "name": "Event Sourcing",
+ "label": "Event Sourcing",
+ "category": "patterns",
+ "description": "Storing all state changes as a sequence of events",
+ "icon": "fas fa-history",
+ "color": "#FDCB6E"
+ },
+ {
+ "key": "ddd",
+ "name": "DDD",
+ "label": "Domain-Driven Design",
+ "category": "patterns",
+ "description": "An approach to software development focused on complex business domains",
+ "icon": "fas fa-project-diagram",
+ "color": "#E17055"
+ },
+ {
+ "key": "graphql",
+ "name": "GraphQL",
+ "label": "GraphQL",
+ "category": "patterns",
+ "description": "A query language for APIs and a runtime for fulfilling those queries",
+ "icon": "devicon-graphql-plain",
+ "color": "#E10098",
+ "website": "https://graphql.org"
+ },
+ {
+ "key": "rest",
+ "name": "REST",
+ "label": "REST API",
+ "category": "patterns",
+ "description": "Representational State Transfer - an architectural style for distributed systems",
+ "icon": "fas fa-plug",
+ "color": "#0D6EFD"
+ },
+ {
+ "key": "grpc",
+ "name": "gRPC",
+ "label": "gRPC",
+ "category": "patterns",
+ "description": "A high-performance, open-source universal RPC framework",
+ "icon": "fas fa-bolt",
+ "color": "#244C5A",
+ "website": "https://grpc.io"
+ },
+ {
+ "key": "binance",
+ "name": "Binance API",
+ "label": "Binance API",
+ "category": "apis",
+ "description": "Cryptocurrency exchange API for trading and market data",
+ "icon": "fas fa-coins",
+ "color": "#F0B90B",
+ "website": "https://binance-docs.github.io/apidocs"
+ },
+ {
+ "key": "deribit",
+ "name": "Deribit API",
+ "label": "Deribit API",
+ "category": "apis",
+ "description": "Cryptocurrency derivatives exchange API for options and futures trading",
+ "icon": "fas fa-chart-line",
+ "color": "#00A859",
+ "website": "https://docs.deribit.com"
+ },
+ {
+ "key": "stripe",
+ "name": "Stripe",
+ "label": "Stripe",
+ "category": "apis",
+ "description": "A suite of payment APIs that powers commerce for businesses of all sizes",
+ "icon": "fab fa-stripe",
+ "color": "#635BFF",
+ "website": "https://stripe.com"
+ },
+ {
+ "key": "twilio",
+ "name": "Twilio",
+ "label": "Twilio",
+ "category": "apis",
+ "description": "Cloud communications platform for SMS, voice, and video",
+ "icon": "fas fa-phone",
+ "color": "#F22F46",
+ "website": "https://www.twilio.com"
+ },
+ {
+ "key": "sendgrid",
+ "name": "SendGrid",
+ "label": "SendGrid",
+ "category": "apis",
+ "description": "A cloud-based email delivery service for transactional and marketing emails",
+ "icon": "fas fa-envelope",
+ "color": "#1A82E2",
+ "website": "https://sendgrid.com"
+ },
+ {
+ "key": "jest",
+ "name": "Jest",
+ "label": "Jest",
+ "category": "testing",
+ "description": "A delightful JavaScript testing framework with a focus on simplicity",
+ "icon": "devicon-jest-plain",
+ "color": "#C21325",
+ "website": "https://jestjs.io"
+ },
+ {
+ "key": "vitest",
+ "name": "Vitest",
+ "label": "Vitest",
+ "category": "testing",
+ "description": "A Vite-native unit test framework with a focus on speed",
+ "icon": "devicon-vitest-plain",
+ "color": "#6E9F18",
+ "website": "https://vitest.dev"
+ },
+ {
+ "key": "cypress",
+ "name": "Cypress",
+ "label": "Cypress",
+ "category": "testing",
+ "description": "A next-generation front-end testing tool for web applications",
+ "icon": "devicon-cypressio-original",
+ "color": "#17202C",
+ "website": "https://www.cypress.io"
+ },
+ {
+ "key": "playwright",
+ "name": "Playwright",
+ "label": "Playwright",
+ "category": "testing",
+ "description": "A framework for reliable end-to-end testing for modern web apps",
+ "icon": "fas fa-theater-masks",
+ "color": "#2EAD33",
+ "website": "https://playwright.dev"
+ },
+ {
+ "key": "xunit",
+ "name": "xUnit",
+ "label": "xUnit.net",
+ "category": "testing",
+ "description": "A free, open-source unit testing tool for the .NET Framework",
+ "icon": "fas fa-vial",
+ "color": "#512BD4",
+ "website": "https://xunit.net"
+ },
+ {
+ "key": "react-native",
+ "name": "React Native",
+ "label": "React Native",
+ "category": "mobile",
+ "description": "A framework for building native mobile apps using React",
+ "icon": "fab fa-react",
+ "color": "#61DAFB",
+ "website": "https://reactnative.dev"
+ },
+ {
+ "key": "flutter",
+ "name": "Flutter",
+ "label": "Flutter",
+ "category": "mobile",
+ "description": "Google's UI toolkit for building natively compiled applications",
+ "icon": "devicon-flutter-plain",
+ "color": "#02569B",
+ "website": "https://flutter.dev"
+ },
+ {
+ "key": "swift",
+ "name": "Swift",
+ "label": "Swift",
+ "category": "mobile",
+ "description": "Apple's powerful and intuitive programming language for iOS/macOS",
+ "icon": "devicon-swift-plain",
+ "color": "#FA7343",
+ "website": "https://developer.apple.com/swift"
+ },
+ {
+ "key": "kotlin",
+ "name": "Kotlin",
+ "label": "Kotlin",
+ "category": "mobile",
+ "description": "A modern programming language for Android development",
+ "icon": "devicon-kotlin-plain",
+ "color": "#7F52FF",
+ "website": "https://kotlinlang.org"
+ },
+ {
+ "key": "maui",
+ "name": ".NET MAUI",
+ "label": ".NET MAUI",
+ "category": "mobile",
+ "description": "Multi-platform App UI for building cross-platform applications with .NET",
+ "icon": "devicon-dotnetcore-plain",
+ "color": "#512BD4",
+ "website": "https://dotnet.microsoft.com/apps/maui"
+ },
+ {
+ "key": "tailwindcss",
+ "name": "TailwindCSS",
+ "label": "Tailwind CSS",
+ "category": "styling",
+ "description": "A utility-first CSS framework for rapidly building custom designs",
+ "icon": "devicon-tailwindcss-plain",
+ "color": "#06B6D4",
+ "website": "https://tailwindcss.com"
+ },
+ {
+ "key": "sass",
+ "name": "Sass",
+ "label": "Sass/SCSS",
+ "category": "styling",
+ "description": "A mature, stable, and powerful professional grade CSS extension language",
+ "icon": "devicon-sass-original",
+ "color": "#CC6699",
+ "website": "https://sass-lang.com"
+ },
+ {
+ "key": "bootstrap",
+ "name": "Bootstrap",
+ "label": "Bootstrap",
+ "category": "styling",
+ "description": "The most popular HTML, CSS, and JS library in the world",
+ "icon": "devicon-bootstrap-plain",
+ "color": "#7952B3",
+ "website": "https://getbootstrap.com"
+ },
+ {
+ "key": "materialui",
+ "name": "Material UI",
+ "label": "Material UI",
+ "category": "styling",
+ "description": "React components for faster and easier web development",
+ "icon": "devicon-materialui-plain",
+ "color": "#007FFF",
+ "website": "https://mui.com"
+ },
+ {
+ "key": "python",
+ "name": "Python",
+ "label": "Python",
+ "category": "programming-language",
+ "description": "A high-level, general-purpose programming language known for its readability, simplicity, and versatility.",
+ "abbreviation": null,
+ "icon": "fab fa-python",
+ "color": "#3776AB",
+ "website": "https://www.python.org"
+ },
+ {
+ "key": "blockchain",
+ "name": "Blockchain",
+ "label": "Blockchain Technology",
+ "category": "distributed-ledger",
+ "description": "A decentralized, distributed ledger technology that enables secure, transparent, and tamper-resistant record-keeping across cryptocurrencies and dApps.",
+ "abbreviation": null,
+ "icon": "fas fa-link",
+ "color": "#1E88E5",
+ "website": "https://www.ibm.com/topics/what-is-blockchain"
+ },
+ {
+ "key": "pow",
+ "name": "Proof-of-Work",
+ "label": "Proof-of-Work (PoW)",
+ "category": "consensus-mechanism",
+ "description": "A blockchain consensus algorithm requiring computational effort to validate transactions and secure the network against attacks.",
+ "abbreviation": "PoW",
+ "icon": "fas fa-puzzle-piece",
+ "color": "#FF9900",
+ "website": "https://bitcoin.org/en/glossary/proof-of-work"
+ },
+ {
+ "key": "hiveos",
+ "name": "Hive OS",
+ "label": "Hive OS",
+ "category": "mining-platform",
+ "description": "A specialized Linux-based operating system for managing and monitoring large-scale cryptocurrency mining farms (GPU and ASIC rigs).",
+ "abbreviation": null,
+ "icon": "fas fa-server",
+ "color": "#FFA500",
+ "website": "https://hiveon.com/os/"
+ },
+ {
+ "key": "antminer",
+ "name": "Antminer",
+ "label": "Bitmain Antminer",
+ "category": "mining-hardware",
+ "description": "Industry-leading series of ASIC miners for Bitcoin and other SHA-256 cryptocurrencies, widely used in large mining farms.",
+ "abbreviation": null,
+ "icon": "fas fa-microchip",
+ "color": "#000000",
+ "website": "https://www.bitmain.com/"
+ },
+ {
+ "key": "erc20",
+ "name": "ERC-20",
+ "label": "ERC-20 Token Standard",
+ "category": "blockchain-standard",
+ "description": "The most widely used Ethereum token standard for creating fungible tokens, enabling interoperability across wallets, exchanges, and dApps.",
+ "abbreviation": "ERC-20",
+ "icon": "fas fa-coins",
+ "color": "#627EEA",
+ "website": "https://ethereum.org/en/developers/docs/standards/tokens/erc-20/"
+ },
+ {
+ "key": "ethereum",
+ "name": "Ethereum",
+ "label": "Ethereum (ETH)",
+ "category": "blockchain-platform",
+ "description": "A decentralized blockchain platform that enables smart contracts, dApps, and ERC-20 tokens with proof-of-stake consensus.",
+ "abbreviation": "ETH",
+ "icon": "fab fa-ethereum",
+ "color": "#627EEA",
+ "website": "https://ethereum.org"
+ },
+ {
+ "key": "solana",
+ "name": "Solana",
+ "label": "Solana (SOL)",
+ "category": "blockchain-platform",
+ "description": "A high-performance layer-1 blockchain using proof-of-history and proof-of-stake for fast, low-cost transactions and scalable dApps.",
+ "abbreviation": "SOL",
+ "icon": "fas fa-bolt",
+ "color": "#14F195",
+ "website": "https://solana.com"
+ },
+ {
+ "key": "polygon",
+ "name": "Polygon",
+ "label": "Polygon (POL)",
+ "category": "blockchain-layer2",
+ "description": "A layer-2 scaling solution for Ethereum that provides faster and cheaper transactions while maintaining security and compatibility.",
+ "abbreviation": "POL",
+ "icon": "fas fa-cubes",
+ "color": "#8247E5",
+ "website": "https://polygon.technology"
+ },
+ {
+ "key": "team-management",
+ "name": "Team Management",
+ "label": "Team Leadership & Management",
+ "category": "leadership",
+ "description": "Experience in leading, coordinating, and managing hybrid teams (in-person and remote) of up to 7 members, with proven leadership in entrepreneurial environments.",
+ "abbreviation": null,
+ "icon": "fas fa-users-cog",
+ "color": "#4CAF50",
+ "website": null
+ },
+ {
+ "key": "html",
+ "name": "HTML",
+ "label": "HTML5",
+ "category": "markup-language",
+ "description": "The standard markup language for creating and structuring web pages and web applications.",
+ "abbreviation": "HTML",
+ "icon": "fab fa-html5",
+ "color": "#E34F26",
+ "website": "https://html.spec.whatwg.org/"
+ },
+ {
+ "key": "css",
+ "name": "CSS",
+ "label": "CSS3",
+ "category": "styling-language",
+ "description": "A stylesheet language used for describing the presentation and layout of web documents written in HTML.",
+ "abbreviation": "CSS",
+ "icon": "fab fa-css3-alt",
+ "color": "#1572B6",
+ "website": "https://www.w3.org/Style/CSS/"
+ },
+ {
+ "key": "scss",
+ "name": "SCSS",
+ "label": "SCSS (Sass)",
+ "category": "css-preprocessor",
+ "description": "A CSS preprocessor that adds features like variables, nesting, and mixins for more maintainable and powerful stylesheets.",
+ "abbreviation": "SCSS",
+ "icon": "fab fa-sass",
+ "color": "#CC6699",
+ "website": "https://sass-lang.com"
+ },
+ {
+ "key": "json",
+ "name": "JSON",
+ "label": "JSON",
+ "category": "data-format",
+ "description": "A lightweight data-interchange format that is easy for humans to read and write, and easy for machines to parse and generate.",
+ "abbreviation": "JSON",
+ "icon": "fas fa-file-code",
+ "color": "#000000",
+ "website": "https://www.json.org"
+ },
+ {
+ "key": "binance-api",
+ "name": "Binance API",
+ "label": "Binance API",
+ "category": "crypto-exchange-api",
+ "description": "Official REST and WebSocket API provided by Binance for programmatic trading, market data access, and account management on the world's largest cryptocurrency exchange.",
+ "abbreviation": null,
+ "icon": "fas fa-exchange-alt",
+ "color": "#F0B90B",
+ "website": "https://github.com/binance/binance-spot-api-docs"
+ },
+ {
+ "key": "ethical-hacking",
+ "name": "Ethical Hacking",
+ "label": "Ethical Hacking / Penetration Testing",
+ "category": "cybersecurity",
+ "description": "Authorized testing of systems and networks to identify vulnerabilities and improve security (also known as white-hat hacking or penetration testing).",
+ "abbreviation": null,
+ "icon": "fas fa-shield-alt",
+ "color": "#00FF00",
+ "website": "https://www.eccouncil.org/programs/certified-ethical-hacker-ceh/"
+ },
+ {
+ "key": "figma",
+ "name": "Figma",
+ "label": "Figma",
+ "category": "styling",
+ "description": "A collaborative web-based design tool for UI/UX design",
+ "icon": "devicon-figma-plain",
+ "color": "#F24E1E",
+ "website": "https://www.figma.com"
+ },
+ {
+ "key": "adobe-suite",
+ "name": "Adobe Suite",
+ "label": "Adobe Creative Suite",
+ "category": "styling",
+ "description": "Professional creative software including Photoshop, Illustrator, and more",
+ "icon": "devicon-photoshop-plain",
+ "color": "#FF0000",
+ "website": "https://www.adobe.com/creativecloud.html"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes.json
new file mode 100644
index 0000000000000000000000000000000000000000..ab8c86b99aef838a53f5b90f6da585a7e85ad2e2
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes.json
@@ -0,0 +1,54 @@
+{
+ "themes": [
+ {
+ "name": "Professional",
+ "slug": "professional",
+ "description": "Polished dark theme with subtle accents for professional impact",
+ "previewColor": "#00D4FF",
+ "icon": "◆",
+ "isDefault": true,
+ "order": 0,
+ "cssFile": "theme.professional.json"
+ },
+ {
+ "name": "Normal Cyber",
+ "slug": "normal",
+ "description": "Balanced neon glow with teal-cyan palette",
+ "previewColor": "#00d4ff",
+ "icon": "⚡",
+ "isDefault": false,
+ "order": 1,
+ "cssFile": "theme.normal.json"
+ },
+ {
+ "name": "Neon Cyber",
+ "slug": "neon",
+ "description": "Maximum intensity glow effects",
+ "previewColor": "#00ffff",
+ "icon": "✨",
+ "isDefault": false,
+ "order": 2,
+ "cssFile": "theme.neon.json"
+ },
+ {
+ "name": "Minimal",
+ "slug": "minimal",
+ "description": "Reduced effects, clean appearance",
+ "previewColor": "#0099ff",
+ "icon": "○",
+ "isDefault": false,
+ "order": 3,
+ "cssFile": "theme.minimal.json"
+ },
+ {
+ "name": "Glass",
+ "slug": "glass",
+ "description": "Ultra glassmorphism with soft glow",
+ "previewColor": "#7dd3fc",
+ "icon": "◇",
+ "isDefault": false,
+ "order": 4,
+ "cssFile": "theme.glass.json"
+ }
+ ]
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.glass.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.glass.json
new file mode 100644
index 0000000000000000000000000000000000000000..ef2ae100620f8ce28f541ee833bf68244cb18920
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.glass.json
@@ -0,0 +1,3 @@
+{
+ "cssContent": "/* Glass Theme - Ultra glassmorphism with soft glow */\n[data-cyber-theme=\"glass\"] {\n --theme-primary: var(--neon-primary, #00d4ff);\n --theme-glow: var(--glow-soft, 0 0 12px rgba(0, 212, 255, 0.4));\n --theme-border: rgba(255, 255, 255, 0.1);\n --glass-blur: var(--glass-blur-ultra, blur(32px));\n \n /* Enhanced glass surfaces */\n --bg-surface: rgba(15, 20, 30, 0.3);\n --bg-surface-light: rgba(20, 25, 35, 0.2);\n\n /* Accent colors */\n --accent: #7dd3fc;\n --accent-muted: #38bdf8;\n --accent-dark: #0ea5e9;\n\n /* Backgrounds (Glass Specific) */\n --bg-primary: #0a0e17; /* Keep dark base */\n --bg-secondary: rgba(15, 23, 42, 0.4);\n --bg-card: rgba(255, 255, 255, 0.05);\n --bg-card-elevated: rgba(255, 255, 255, 0.08);\n\n /* High contrast text - Light for glass */\n --text-primary: #ffffff;\n --text-secondary: #e0f2fe;\n --text-muted: #bae6fd;\n\n /* Borders */\n --border-color: rgba(255, 255, 255, 0.1);\n --border-color-hover: rgba(255, 255, 255, 0.2);\n\n /* Admin semantic variables */\n --admin-panel-bg: rgba(255, 255, 255, 0.08);\n --admin-panel-border: rgba(255, 255, 255, 0.15);\n --admin-card-bg: rgba(255, 255, 255, 0.08);\n --admin-input-bg: rgba(0, 0, 0, 0.2);\n --admin-text-primary: #ffffff;\n --admin-text-secondary: #cbd5e1;\n}\n\n/* Glass mode panel styling - translucent with heavy blur */\n[data-cyber-theme=\"glass\"] .panel-cyber,\n[data-cyber-theme=\"glass\"] .card-cyber {\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.01));\n backdrop-filter: blur(24px);\n -webkit-backdrop-filter: blur(24px);\n border: 1px solid rgba(255, 255, 255, 0.08);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.37), inset 0 0 0 1px rgba(255, 255, 255, 0.02);\n}\n\n[data-cyber-theme=\"glass\"] .panel-cyber:hover,\n[data-cyber-theme=\"glass\"] .card-cyber:hover {\n background: linear-gradient(135deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.02));\n border-color: rgba(255, 255, 255, 0.15);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45), 0 0 20px rgba(125, 211, 252, 0.2);\n transform: translateY(-6px);\n}\n\n/* Glass mode text styling - soft glow */\n[data-cyber-theme=\"glass\"] .text-theme-primary {\n color: #7dd3fc;\n}\n\n[data-cyber-theme=\"glass\"] .text-theme-glow {\n color: #7dd3fc;\n text-shadow: 0 0 20px rgba(125, 211, 252, 0.5);\n}\n\n/* Glass mode button styling - translucent */\n[data-cyber-theme=\"glass\"] .btn-theme {\n background: linear-gradient(135deg, rgba(125, 211, 252, 0.3), rgba(125, 211, 252, 0.1));\n backdrop-filter: blur(12px);\n color: white;\n border: 1px solid rgba(255, 255, 255, 0.1);\n box-shadow: 0 0 20px rgba(125, 211, 252, 0.2);\n}\n\n[data-cyber-theme=\"glass\"] .btn-theme:hover {\n background: linear-gradient(135deg, rgba(125, 211, 252, 0.4), rgba(125, 211, 252, 0.2));\n box-shadow: 0 0 30px rgba(125, 211, 252, 0.4);\n transform: translateY(-2px);\n}\n\n/* Glass mode special - frosted glass effect */\n[data-cyber-theme=\"glass\"] .glass-frost {\n background: rgba(255, 255, 255, 0.05);\n backdrop-filter: blur(20px) saturate(180%);\n -webkit-backdrop-filter: blur(20px) saturate(180%);\n}"
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.minimal.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.minimal.json
new file mode 100644
index 0000000000000000000000000000000000000000..b71ba43e2619a47f7cf5352437deacd83034071a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.minimal.json
@@ -0,0 +1,3 @@
+{
+ "cssContent": "/* Minimal Theme - Reduced effects, clean appearance */\n[data-cyber-theme=\"minimal\"] {\n --theme-primary: var(--neon-blue, #0099ff);\n --theme-glow: var(--glow-soft, 0 0 12px rgba(0, 212, 255, 0.4));\n --theme-border: var(--border-neon, rgba(0, 212, 255, 0.2));\n --glass-blur: var(--glass-blur-light, blur(8px));\n \n /* Disable some effects */\n --glow-layered: none;\n --gradient-shine: none;\n\n /* Accent colors */\n --accent: #0099ff;\n --accent-muted: #3b82f6;\n --accent-dark: #1d4ed8;\n\n /* Backgrounds */\n --bg-primary: #0f172a;\n --bg-secondary: #1e293b;\n --bg-card: rgba(30, 41, 59, 0.5);\n --bg-card-elevated: rgba(51, 65, 85, 0.6);\n\n /* High contrast text */\n --text-primary: #f1f5f9;\n --text-secondary: #cbd5e1;\n --text-muted: #94a3b8;\n\n /* Borders */\n --border-color: rgba(0, 153, 255, 0.2);\n --border-color-hover: rgba(0, 153, 255, 0.4);\n\n /* Admin semantic variables */\n --admin-panel-bg: rgba(255, 255, 255, 0.02);\n --admin-panel-border: rgba(255, 255, 255, 0.1);\n --admin-card-bg: rgba(255, 255, 255, 0.02);\n --admin-input-bg: rgba(0, 0, 0, 0.2);\n --admin-text-primary: #f8fafc;\n --admin-text-secondary: #94a3b8;\n}\n\n/* Minimal mode panel styling - clean, subtle */\n[data-cyber-theme=\"minimal\"] .panel-cyber,\n[data-cyber-theme=\"minimal\"] .card-cyber {\n background: var(--bg-surface-dark, rgba(10, 15, 25, 0.8));\n border: 1px solid rgba(0, 153, 255, 0.2);\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);\n}\n\n[data-cyber-theme=\"minimal\"] .panel-cyber:hover,\n[data-cyber-theme=\"minimal\"] .card-cyber:hover {\n border-color: rgba(0, 153, 255, 0.4);\n box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);\n transform: translateY(-4px);\n}\n\n/* Minimal mode text styling - no glow */\n[data-cyber-theme=\"minimal\"] .text-theme-primary {\n color: var(--neon-blue, #0099ff);\n}\n\n[data-cyber-theme=\"minimal\"] .text-theme-glow {\n color: var(--neon-blue, #0099ff);\n text-shadow: none;\n}\n\n/* Minimal mode button styling - flat design */\n[data-cyber-theme=\"minimal\"] .btn-theme {\n background: var(--neon-blue, #0099ff);\n color: white;\n border: none;\n box-shadow: none;\n}\n\n[data-cyber-theme=\"minimal\"] .btn-theme:hover {\n background: #007acc;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n transform: translateY(-2px);\n}\n\n/* Disable animations in minimal mode */\n[data-cyber-theme=\"minimal\"] .shimmer-neon,\n[data-cyber-theme=\"minimal\"] .glow-pulse,\n[data-cyber-theme=\"minimal\"] .border-neon-pulse {\n animation: none;\n}"
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.neon.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.neon.json
new file mode 100644
index 0000000000000000000000000000000000000000..cb3fc969e060a7f43e6414771c4c5366b389f920
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.neon.json
@@ -0,0 +1,3 @@
+{
+ "cssContent": "/* Neon Cyber Theme - Maximum intensity glow */\n[data-cyber-theme=\"neon\"] {\n --theme-primary: var(--neon-cyan, #00ffff);\n --theme-glow: var(--glow-strong, 0 0 24px rgba(0, 212, 255, 0.9));\n --theme-border: var(--border-neon-glow, rgba(0, 212, 255, 0.8));\n --glass-blur: var(--glass-blur-light, blur(8px));\n\n /* Accent colors */\n --accent: #00ffff;\n --accent-muted: #00d4ff;\n --accent-dark: #00a3cc;\n\n /* Backgrounds */\n --bg-primary: #050a10;\n --bg-secondary: #0a0f1e;\n --bg-card: rgba(10, 15, 25, 0.85);\n --bg-card-elevated: rgba(20, 30, 40, 0.9);\n\n /* High contrast text */\n --text-primary: #e0f2fe;\n --text-secondary: #bae6fd;\n --text-muted: #7dd3fc;\n\n /* Borders */\n --border-color: rgba(0, 255, 255, 0.3);\n --border-color-hover: rgba(0, 255, 255, 0.6);\n\n /* Admin semantic variables */\n --admin-panel-bg: rgba(20, 30, 40, 0.85);\n --admin-panel-border: rgba(0, 255, 255, 0.4);\n --admin-card-bg: rgba(20, 30, 40, 0.85);\n --admin-input-bg: rgba(0, 0, 0, 0.6);\n --admin-text-primary: #e0f2fe;\n --admin-text-secondary: #bae6fd;\n}\n\n/* Neon mode panel styling - enhanced glow */\n[data-cyber-theme=\"neon\"] .panel-cyber,\n[data-cyber-theme=\"neon\"] .card-cyber {\n background: var(--bg-surface, rgba(15, 20, 30, 0.65));\n border: 1px solid var(--neon-primary, #00d4ff);\n box-shadow: 0 0 20px rgba(0, 255, 255, 0.5), 0 8px 32px rgba(0, 0, 0, 0.5);\n}\n\n[data-cyber-theme=\"neon\"] .panel-cyber:hover,\n[data-cyber-theme=\"neon\"] .card-cyber:hover {\n border-color: var(--neon-cyan, #00ffff);\n box-shadow: 0 0 30px rgba(0, 255, 255, 0.7), 0 0 60px rgba(0, 212, 255, 0.3), 0 12px 40px rgba(0, 0, 0, 0.6);\n transform: translateY(-8px);\n}\n\n/* Neon mode text styling - strong glow */\n[data-cyber-theme=\"neon\"] .text-theme-primary {\n color: var(--neon-cyan, #00ffff);\n}\n\n[data-cyber-theme=\"neon\"] .text-theme-glow {\n color: var(--neon-cyan, #00ffff);\n text-shadow: 0 0 10px rgba(0, 255, 255, 0.8), 0 0 20px rgba(0, 255, 255, 0.5), 0 0 30px rgba(0, 255, 255, 0.3);\n}\n\n/* Neon mode button styling - intense glow */\n[data-cyber-theme=\"neon\"] .btn-theme {\n background: linear-gradient(135deg, #00ffff 0%, #00d4ff 100%);\n color: #0a0e17;\n border: none;\n box-shadow: 0 0 20px rgba(0, 255, 255, 0.5);\n}\n\n[data-cyber-theme=\"neon\"] .btn-theme:hover {\n box-shadow: 0 0 30px rgba(0, 255, 255, 0.7);\n transform: translateY(-3px);\n}\n\n/* Neon mode special accents */\n[data-cyber-theme=\"neon\"] .accent-glow {\n animation: neon-pulse 2s ease-in-out infinite;\n}\n\n@keyframes neon-pulse {\n 0%, 100% { box-shadow: 0 0 10px rgba(0, 255, 255, 0.5); }\n 50% { box-shadow: 0 0 30px rgba(0, 255, 255, 0.9); }\n}"
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.normal.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.normal.json
new file mode 100644
index 0000000000000000000000000000000000000000..6106df18025c9f5d32b11b8f28976ed264dae2ce
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.normal.json
@@ -0,0 +1,3 @@
+{
+ "cssContent": "/* Normal Cyber Theme - Balanced neon glow */\n[data-cyber-theme=\"normal\"] {\n --theme-primary: var(--neon-primary, #00d4ff);\n --theme-glow: var(--glow-medium, 0 0 16px rgba(0, 212, 255, 0.7));\n --theme-border: var(--border-neon, rgba(0, 212, 255, 0.2));\n --glass-blur: var(--glass-blur-medium, blur(16px));\n \n /* Accent colors */\n --accent: #00d4ff;\n --accent-muted: #00b8e6;\n --accent-dark: #0099cc;\n\n /* Backgrounds */\n --bg-primary: #0f172a;\n --bg-secondary: #1e293b;\n --bg-card: rgba(30, 41, 59, 0.75);\n --bg-card-elevated: rgba(51, 65, 85, 0.8);\n\n /* High contrast text */\n --text-primary: #f8fafc;\n --text-secondary: #cbd5e1;\n --text-muted: #94a3b8;\n\n /* Borders */\n --border-color: rgba(0, 212, 255, 0.2);\n --border-color-hover: rgba(0, 212, 255, 0.4);\n\n /* Admin semantic variables */\n --admin-panel-bg: rgba(30, 41, 59, 0.65);\n --admin-panel-border: rgba(0, 212, 255, 0.2);\n --admin-card-bg: rgba(30, 41, 59, 0.65);\n --admin-input-bg: rgba(10, 15, 25, 0.8);\n --admin-text-primary: #e0e7ff;\n --admin-text-secondary: #94a3b8;\n}\n\n/* Normal mode panel styling */\n[data-cyber-theme=\"normal\"] .panel-cyber,\n[data-cyber-theme=\"normal\"] .card-cyber {\n background: var(--bg-surface, rgba(15, 20, 30, 0.65));\n border: 1px solid var(--border-neon, rgba(0, 212, 255, 0.2));\n box-shadow: var(--shadow-neon-md, 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 12px rgba(0, 212, 255, 0.3));\n}\n\n[data-cyber-theme=\"normal\"] .panel-cyber:hover,\n[data-cyber-theme=\"normal\"] .card-cyber:hover {\n border-color: var(--border-neon-bright, rgba(0, 212, 255, 0.5));\n box-shadow: var(--shadow-neon-lg, 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 20px rgba(0, 212, 255, 0.4));\n}\n\n/* Normal mode text styling */\n[data-cyber-theme=\"normal\"] .text-theme-primary {\n color: var(--neon-primary, #00d4ff);\n}\n\n[data-cyber-theme=\"normal\"] .text-theme-glow {\n color: var(--neon-primary, #00d4ff);\n text-shadow: var(--glow-medium, 0 0 16px rgba(0, 212, 255, 0.7));\n}\n\n/* Normal mode button styling */\n[data-cyber-theme=\"normal\"] .btn-theme {\n background: linear-gradient(135deg, #00d4ff 0%, #00ffff 100%);\n color: #0a0e17;\n border: none;\n box-shadow: 0 0 12px rgba(0, 212, 255, 0.4);\n}\n\n[data-cyber-theme=\"normal\"] .btn-theme:hover {\n box-shadow: 0 0 20px rgba(0, 212, 255, 0.6);\n transform: translateY(-2px);\n}"
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.professional.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.professional.json
new file mode 100644
index 0000000000000000000000000000000000000000..aaada658296939dca285119a6ec2d39d0a3cdf61
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/JsonDatas/themes/theme.professional.json
@@ -0,0 +1,3 @@
+{
+ "cssContent": "/* Professional Theme - Polished dark with teal accents */\n[data-cyber-theme=\"professional\"] {\n /* Primary accent colors */\n --theme-primary: #00D4FF;\n --theme-glow: 0 0 8px rgba(0, 212, 255, 0.3);\n --theme-border: rgba(51, 65, 85, 0.6);\n --glass-blur: blur(12px);\n \n /* Accent colors */\n --accent: #00D4FF;\n --accent-muted: #06B6D4;\n --accent-dark: #0891B2;\n \n /* Backgrounds */\n --bg-primary: #0A0E17;\n --bg-secondary: #0F172A;\n --bg-card: rgba(15, 23, 42, 0.85);\n --bg-card-elevated: rgba(30, 41, 59, 0.9);\n \n /* High contrast text */\n --text-primary: #F1F5F9;\n --text-secondary: #94A3B8;\n --text-muted: #64748B;\n \n /* Borders */\n --border-color: rgba(51, 65, 85, 0.6);\n --border-color-hover: rgba(0, 212, 255, 0.4);\n \n /* Admin variables */\n --admin-panel-bg: rgba(15, 23, 42, 0.9);\n --admin-panel-border: rgba(51, 65, 85, 0.6);\n --admin-card-bg: rgba(30, 41, 59, 0.85);\n --admin-input-bg: rgba(10, 15, 25, 0.9);\n --admin-text-primary: #F1F5F9;\n --admin-text-secondary: #94A3B8;\n}\n\n/* ============================================\n Tab Control Styling\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .tab-control {\n --tab-container-bg: rgba(15, 23, 42, 0.85);\n --tab-container-border: rgba(51, 65, 85, 0.6);\n --tab-bg: transparent;\n --tab-bg-hover: rgba(0, 212, 255, 0.1);\n --tab-bg-active: #00D4FF;\n --tab-text: #94A3B8;\n --tab-text-hover: #F1F5F9;\n --tab-text-active: #0A0E17;\n --tab-shadow-active: 0 2px 8px rgba(0, 212, 255, 0.3);\n}\n\n/* ============================================\n Dashboard Stat Cards\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .stat-card {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1rem;\n padding: 1.5rem;\n}\n\n[data-cyber-theme=\"professional\"] .stat-card:hover {\n border-color: rgba(0, 212, 255, 0.5);\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);\n}\n\n[data-cyber-theme=\"professional\"] .stat-label {\n color: #94A3B8;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n[data-cyber-theme=\"professional\"] .stat-value {\n color: #F1F5F9;\n font-size: 2rem;\n font-weight: 700;\n}\n\n/* ============================================\n Timeline / Experience Cards\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .timeline-card {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1rem;\n padding: 2rem;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-card:hover {\n border-color: #00D4FF;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);\n}\n\n/* Date Badge - Teal filled */\n[data-cyber-theme=\"professional\"] .timeline-card-date {\n background: #00D4FF;\n color: #0A0E17;\n padding: 0.375rem 0.75rem;\n border-radius: 9999px;\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-card-date[data-current=\"true\"] {\n background: #10B981;\n color: #FFFFFF;\n}\n\n/* Type Badge - Teal outline */\n[data-cyber-theme=\"professional\"] .timeline-type-badge {\n padding: 0.375rem 0.75rem;\n font-size: 0.6875rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n border-radius: 0.375rem;\n background: transparent;\n border: 1px solid;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-type-badge[data-type=\"experience\"] {\n color: #00D4FF;\n border-color: #00D4FF;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-type-badge[data-type=\"education\"] {\n color: #10B981;\n border-color: #10B981;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-type-badge[data-type=\"achievement\"] {\n color: #F59E0B;\n border-color: #F59E0B;\n}\n\n/* Card Content Text */\n[data-cyber-theme=\"professional\"] .timeline-card-title {\n font-size: 1.25rem;\n font-weight: 700;\n color: #FFFFFF;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-card-org {\n font-size: 0.9375rem;\n color: #94A3B8;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-card-org svg {\n color: #64748B;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-card-desc {\n font-size: 0.9375rem;\n color: #CBD5E1;\n line-height: 1.75;\n}\n\n/* Technology Badges */\n[data-cyber-theme=\"professional\"] .timeline-card-skills {\n border-top: 1px solid rgba(51, 65, 85, 0.6);\n padding-top: 1.25rem;\n margin-top: 1.25rem;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-card-skills .tech-badge,\n[data-cyber-theme=\"professional\"] .tech-badge {\n padding: 0.375rem 0.75rem;\n font-size: 0.8125rem;\n font-weight: 500;\n color: #F1F5F9;\n background: rgba(30, 41, 59, 0.8);\n border: 1px solid rgba(148, 163, 184, 0.4);\n border-radius: 0.375rem;\n}\n\n[data-cyber-theme=\"professional\"] .timeline-card-skills .tech-badge:hover,\n[data-cyber-theme=\"professional\"] .tech-badge:hover {\n border-color: #00D4FF;\n background: rgba(0, 212, 255, 0.1);\n color: #FFFFFF;\n}\n\n/* ============================================\n Skill Category Cards\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .resume-skill-category {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1rem;\n}\n\n[data-cyber-theme=\"professional\"] .resume-skill-category:hover {\n border-color: #00D4FF;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);\n}\n\n[data-cyber-theme=\"professional\"] .resume-skill-category-header {\n border-bottom: 1px solid rgba(51, 65, 85, 0.6);\n padding: 1.25rem;\n}\n\n[data-cyber-theme=\"professional\"] .resume-skill-category-name {\n font-size: 1.125rem;\n font-weight: 700;\n color: #F1F5F9;\n}\n\n[data-cyber-theme=\"professional\"] .resume-skill-item {\n padding: 0.375rem 0.75rem;\n background: rgba(30, 41, 59, 0.8);\n border: 1px solid rgba(148, 163, 184, 0.4);\n border-radius: 0.375rem;\n font-size: 0.8125rem;\n font-weight: 500;\n color: #F1F5F9;\n}\n\n[data-cyber-theme=\"professional\"] .resume-skill-item:hover {\n border-color: #00D4FF;\n background: rgba(0, 212, 255, 0.1);\n}\n\n/* ============================================\n Language Cards\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .resume-language-card {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1rem;\n padding: 1.5rem;\n}\n\n[data-cyber-theme=\"professional\"] .resume-language-card:hover {\n border-color: #00D4FF;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);\n}\n\n[data-cyber-theme=\"professional\"] .resume-language-card .language-name {\n font-size: 1.25rem;\n font-weight: 700;\n color: #F1F5F9;\n}\n\n[data-cyber-theme=\"professional\"] .resume-language-card .skill-label {\n color: #94A3B8;\n}\n\n/* ============================================\n Domain Cards\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .resume-domain-card {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1rem;\n padding: 1.5rem;\n}\n\n[data-cyber-theme=\"professional\"] .resume-domain-card:hover {\n border-color: #00D4FF;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);\n}\n\n[data-cyber-theme=\"professional\"] .resume-domain-card .domain-icon {\n width: 48px;\n height: 48px;\n background: rgba(0, 212, 255, 0.15);\n border: 1px solid rgba(0, 212, 255, 0.3);\n border-radius: 0.75rem;\n color: #00D4FF;\n}\n\n[data-cyber-theme=\"professional\"] .resume-domain-card .domain-name {\n font-size: 1.25rem;\n font-weight: 700;\n color: #F1F5F9;\n}\n\n[data-cyber-theme=\"professional\"] .resume-domain-card .domain-years {\n color: #94A3B8;\n}\n\n[data-cyber-theme=\"professional\"] .resume-domain-card .domain-level {\n background: #00D4FF;\n color: #0A0E17;\n padding: 0.375rem 1rem;\n border-radius: 9999px;\n font-size: 0.6875rem;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n[data-cyber-theme=\"professional\"] .resume-domain-card .domain-description {\n color: #94A3B8;\n border-top: 1px solid rgba(51, 65, 85, 0.6);\n padding-top: 0.75rem;\n margin-top: 0.75rem;\n}\n\n/* ============================================\n Hobby Cards\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .resume-hobby-card {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1rem;\n padding: 1.25rem;\n}\n\n[data-cyber-theme=\"professional\"] .resume-hobby-card:hover {\n border-color: #00D4FF;\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);\n}\n\n[data-cyber-theme=\"professional\"] .resume-hobby-card .hobby-icon {\n width: 48px;\n height: 48px;\n background: rgba(0, 212, 255, 0.15);\n border: 1px solid rgba(0, 212, 255, 0.3);\n color: #00D4FF;\n border-radius: 0.75rem;\n}\n\n[data-cyber-theme=\"professional\"] .resume-hobby-card .hobby-name {\n font-size: 1.125rem;\n font-weight: 700;\n color: #F1F5F9;\n}\n\n[data-cyber-theme=\"professional\"] .resume-hobby-card .hobby-description {\n color: #94A3B8;\n}\n\n/* ============================================\n Project Cards\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .project-card {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1rem;\n}\n\n[data-cyber-theme=\"professional\"] .project-card:hover {\n border-color: #00D4FF;\n box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);\n}\n\n[data-cyber-theme=\"professional\"] .project-card-status,\n[data-cyber-theme=\"professional\"] .project-card-footer .tech-label {\n color: #00D4FF;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n[data-cyber-theme=\"professional\"] .tech-more {\n color: #00D4FF;\n background: rgba(0, 212, 255, 0.1);\n}\n\n/* ============================================\n Hero Summary Card\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .resume-summary {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n border-radius: 1.5rem;\n padding: 2.5rem;\n color: #94A3B8;\n}\n\n/* ============================================\n Buttons\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .btn-theme {\n background: linear-gradient(135deg, #00D4FF 0%, #06B6D4 100%);\n color: #0A0E17;\n border: none;\n box-shadow: 0 2px 8px rgba(0, 212, 255, 0.3);\n font-weight: 600;\n}\n\n[data-cyber-theme=\"professional\"] .btn-theme:hover {\n box-shadow: 0 4px 16px rgba(0, 212, 255, 0.4);\n transform: translateY(-2px);\n}\n\n/* ============================================\n Panels and Cards - Generic\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .panel-cyber,\n[data-cyber-theme=\"professional\"] .card-cyber {\n background: rgba(15, 23, 42, 0.85);\n border: 1px solid rgba(51, 65, 85, 0.6);\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);\n backdrop-filter: blur(12px);\n}\n\n[data-cyber-theme=\"professional\"] .panel-cyber:hover,\n[data-cyber-theme=\"professional\"] .card-cyber:hover {\n border-color: #00D4FF;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);\n}\n\n/* ============================================\n Text Utilities\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .text-theme-primary {\n color: #00D4FF;\n}\n\n[data-cyber-theme=\"professional\"] .text-theme-glow {\n color: #00D4FF;\n text-shadow: 0 0 12px rgba(0, 212, 255, 0.4);\n}\n\n/* ============================================\n Disable aggressive animations\n ============================================ */\n\n[data-cyber-theme=\"professional\"] .shimmer-neon,\n[data-cyber-theme=\"professional\"] .glow-pulse {\n animation: none;\n}\n\n[data-cyber-theme=\"professional\"] .resume-animate-in {\n animation: professionalFadeIn 0.4s ease-out forwards;\n}\n\n@keyframes professionalFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}"
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-alliance-startupcms-ia.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-alliance-startupcms-ia.json
new file mode 100644
index 0000000000000000000000000000000000000000..6f5c874b7ea56c2e6bbaea88a369cd4739228f0b
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-alliance-startupcms-ia.json
@@ -0,0 +1,81 @@
+{
+ "title": "Ark.Alliance.StartupCms.AI",
+ "description": "AI-powered CMS platform designed specifically for startups. Features collaborative profile/resume building with AI assistance, hierarchical team visualization, task tracking with growth-mindset evaluation, partial public visibility of accomplishments, and rich personal sections (experiences, education, skills, hobbies, domains). Built with Next.js 15 App Router, Prisma ORM, TypeScript 5, and Tailwind/Shadcn UI for modern, scalable, human-centric collaboration.",
+ "status": "In Development",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.AI/ArkAllianceStartupCmsAiHero.png",
+ "repoUrl": "https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.StartupCms.AI",
+ "demoUrl": "",
+ "packageUrl": "",
+ "technologies": [
+ "react",
+ "nextjs",
+ "typescript",
+ "prisma",
+ "postgresql",
+ "tailwindcss",
+ "shadcn",
+ "openai",
+ "anthropic",
+ "gemini",
+ "jest",
+ "playwright"
+ ],
+ "features": [
+ {
+ "title": "AI-Assisted Profile & Resume Generation",
+ "description": "Transform natural language descriptions into professional profile sections and comprehensive resumes. Multi-provider AI integration (OpenAI, Anthropic, Gemini) with intelligent prompt templates for profile generation, resume enhancement, and content optimization.",
+ "icon": "brain"
+ },
+ {
+ "title": "Team Hierarchy Organigram",
+ "description": "Visual organizational chart displaying team structure with dynamic hierarchical layouts. Supports multiple organizational levels, role-based permissions, and interactive team member profiles with drill-down capabilities.",
+ "icon": "sitemap"
+ },
+ {
+ "title": "Task Tracking & Evaluation",
+ "description": "Growth-mindset task management system with lesson-learned evaluations. Track tasks, document learnings, celebrate progress, and maintain a culture of continuous improvement aligned with human-centric development principles.",
+ "icon": "tasks"
+ },
+ {
+ "title": "Partial Public Visibility",
+ "description": "Selective disclosure of accomplishments and profile sections. Control what's publicly visible vs. team-internal, enabling professional portfolio showcasing while maintaining privacy for sensitive information.",
+ "icon": "eye"
+ },
+ {
+ "title": "Rich Personal Sections",
+ "description": "Comprehensive profile system with experiences, education, skills (with proficiency levels), hobbies, domain expertise, and custom sections. Supports multimedia content, timeline visualization, and structured data rendering.",
+ "icon": "user-circle"
+ },
+ {
+ "title": "Technology & Skills Display",
+ "description": "Technology badges with category-based organization, proficiency indicators, and years of experience tracking. Visual skill matrices and technology stack documentation for team capabilities and project requirements.",
+ "icon": "code"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "# Ark.Alliance.StartupCms.AI – Application Overview & Architecture\n\n**Last Updated**: January 07, 2026 \n**Version**: 1.0.0\n\n## Introduction\n\n**Ark.Alliance.StartupCms.AI** is an AI-powered content management system built specifically for startups. It combines collaborative profile building, AI-assisted content generation, hierarchical team management, and growth-mindset task tracking into a unified platform that emphasizes human-centric design and continuous improvement.\n\n### Core Philosophy\n\nBuilt on the conviction that technology should amplify human potential, this platform integrates:\n\n- 🧠 **AI Augmentation**: AI assists but never replaces human creativity and decision-making\n- 🌱 **Growth Mindset**: Continuous learning through task evaluation and lesson documentation\n- 🤝 **Collaborative Excellence**: Team-based profile building with transparent hierarchies\n- 🎯 **Selective Transparency**: Control what's public vs. team-internal for professional portfolios\n\n### Perfect For\n\n- 🚀 **Startup Teams** — Collaborative profile management and team showcasing\n- 💼 **Growing Organizations** — Hierarchical team structures with clear role definitions\n- 🎓 **Portfolio Building** — AI-assisted resume and profile generation\n- 📊 **Team Analytics** — Track skills, expertise, and organizational capabilities\n- 🌍 **Public Engagement** — Selectively showcase team accomplishments and expertise\n\n### Key Statistics\n\n- **Built on**: Next.js 15 App Router\n- **Database**: Prisma ORM with PostgreSQL\n- **Type Safety**: End-to-end TypeScript 5.x\n- **Styling**: Tailwind CSS + Shadcn UI\n- **AI Providers**: OpenAI, Anthropic, Google Gemini\n\n## Table of Contents\n\n1. [Core Functionalities Overview](#core-functionalities-overview)\n2. [AI-Assisted Profile & Resume Generation](#ai-assisted-profile-resume-generation)\n3. [Team Hierarchy Organigram](#team-hierarchy-organigram)\n4. [Task Tracking & Evaluation](#task-tracking-evaluation)\n5. [Partial Public Visibility](#partial-public-visibility)\n6. [Rich Personal Sections Rendering](#rich-personal-sections-rendering)\n7. [Technology & Skills Display](#technology-skills-display)\n8. [Architecture Overview](#architecture-overview)\n9. [Development Lifecycle & Quality Assurance](#development-lifecycle-quality-assurance)\n10. [Best Practices & Philosophy](#best-practices-philosophy)\n\n---\n\n## Core Functionalities Overview\n\n| Functionality | Description | User Benefits |\n|---------------|-------------|---------------|\n| **AI Profile Generation** | Natural language to professional profile | Save time, maintain consistency |\n| **Team Organigram** | Visual hierarchical team structure | Clear reporting lines, role clarity |\n| **Task System** | Growth-mindset task tracking | Continuous improvement culture |\n| **Visibility Control** | Public/private section toggles | Professional portfolios + privacy |\n| **Personal Sections** | Experiences, education, skills, hobbies | Comprehensive team profiles |\n| **Tech Stack Display** | Technology badges and skill matrices | Capability documentation |"
+ },
+ {
+ "title": "Detailed Functionalities",
+ "type": "FUNCTIONAL",
+ "navOrder": 2,
+ "content": "## AI-Assisted Profile & Resume Generation\n\n### Description\n\nTransform simple text descriptions into polished, professional profile content. The system uses multi-provider AI (OpenAI GPT-4, Anthropic Claude, Google Gemini) with intelligent prompt templates to generate:\n\n- Professional profile summaries from brief descriptions\n- Enhanced resume sections (experience, education, skills)\n- Optimized content for clarity and impact\n- Consistent tone and formatting across profiles\n\n### User Benefits\n\n✅ **Time Savings**: Generate professional content in seconds, not hours \n✅ **Consistency**: Maintain uniform quality across all team profiles \n✅ **AI Flexibility**: Choose the best AI provider for your use case \n✅ **Iterative Refinement**: Generate, review, and refine with AI assistance\n\n### User/Data Flow\n\n```mermaid\nflowchart TD\n Start([User provides text description]) --> Submit[Submit to AI Profile Service]\n Submit --> Select{Select AI Provider}\n Select -->|OpenAI| GPT[GPT-4 Processing]\n Select -->|Anthropic| Claude[Claude 3 Processing]\n Select -->|Gemini| Gemini[Gemini 1.5 Processing]\n \n GPT --> Process[Apply Prompt Template]\n Claude --> Process\n Gemini --> Process\n \n Process --> Generate[Generate Professional Content]\n Generate --> Review{User Reviews}\n Review -->|Approve| Save[(Save to Profile)]\n Review -->|Refine| Submit\n Save --> Render[Render in UI]\n \n style Start fill:#10b981,stroke:#059669,color:#fff\n style Save fill:#3b82f6,stroke:#2563eb,color:#fff\n style Render fill:#10b981,stroke:#059669,color:#fff\n style Review fill:#f59e0b,stroke:#d97706,color:#000\n```\n\n---\n\n## Team Hierarchy Organigram\n\n### Description\n\nVisualize your organization's structure with an interactive hierarchical chart. The organigram displays:\n\n- Multi-level organizational hierarchy (CEO → Managers → Team Members)\n- Role and title visualization\n- Interactive drill-down to team member profiles\n- Dynamic layout based on team composition\n\n### User Benefits\n\n✅ **Clear Structure**: Instantly understand reporting lines and team organization \n✅ **Onboarding Tool**: Help new team members understand the organization \n✅ **Profile Access**: One-click navigation to detailed team member profiles \n✅ **Scalability**: Supports teams from 5 to 500+ members\n\n### User/Data Flow\n\n```mermaid\nflowchart TB\n Load([Load Team Page]) --> Fetch[Fetch Team Structure]\n Fetch --> Parse[Parse Hierarchical Data]\n Parse --> Build[Build Organization Tree]\n Build --> Layout{Calculate Layout}\n Layout --> Render[Render Organigram]\n \n Render --> Interact{User Interaction}\n Interact -->|Click Member| Profile[Navigate to Profile]\n Interact -->|Hover| Tooltip[Show Quick Info]\n Interact -->|Expand| SubTeam[Show Sub-Teams]\n \n Profile --> Display[Display Full Resume]\n Tooltip --> Render\n SubTeam --> Layout\n \n style Load fill:#10b981,stroke:#059669,color:#fff\n style Render fill:#3b82f6,stroke:#2563eb,color:#fff\n style Profile fill:#8b5cf6,stroke:#7c3aed,color:#fff\n```\n\n---\n\n## Task Tracking & Evaluation\n\n### Description\n\nGrowth-mindset task management that emphasizes learning over mere completion. Features:\n\n- Task creation with detailed descriptions and acceptance criteria\n- Status tracking (Todo, In Progress, Done)\n- **Lesson-learned evaluations** upon task completion\n- Growth-oriented retrospectives and continuous improvement documentation\n\n### User Benefits\n\n✅ **Growth Culture**: Foster a learning-first environment \n✅ **Knowledge Retention**: Capture lessons and avoid repeated mistakes \n✅ **Team Learning**: Share insights across the team \n✅ **Progress Tracking**: Visualize individual and team growth\n\n### User/Data Flow\n\n```mermaid\nflowchart TD\n Create([Create Task]) --> Define[Define Task Details]\n Define --> Assign[Assign to Team Member]\n Assign --> InProgress[Start Work]\n InProgress --> Complete{Mark Complete}\n \n Complete --> Evaluate[Evaluate: Lessons Learned]\n Evaluate --> Document[Document Insights]\n Document --> Categories{Categorize Learning}\n \n Categories -->|Technical| TechLesson[(Store Technical Lesson)]\n Categories -->|Process| ProcessLesson[(Store Process Lesson)]\n Categories -->|Collaboration| CollabLesson[(Store Collaboration Lesson)]\n \n TechLesson --> Share[Share with Team]\n ProcessLesson --> Share\n CollabLesson --> Share\n \n Share --> Archive[Archive to Knowledge Base]\n Archive --> End([Task Archived])\n \n style Create fill:#10b981,stroke:#059669,color:#fff\n style Evaluate fill:#f59e0b,stroke:#d97706,color:#000\n style Share fill:#3b82f6,stroke:#2563eb,color:#fff\n style End fill:#8b5cf6,stroke:#7c3aed,color:#fff\n```\n\n---\n\n## Partial Public Visibility\n\n### Description\n\nControl what parts of your profile and accomplishments are publicly visible versus team-internal. Features:\n\n- Section-level visibility toggles (Public, Team Only, Private)\n- Selective accomplishment disclosure\n- Public portfolio generation from selected sections\n- Privacy-first design with explicit opt-in for public sharing\n\n### User Benefits\n\n✅ **Privacy Control**: Share only what you're comfortable with \n✅ **Professional Portfolio**: Public-facing resume from selected sections \n✅ **Team Transparency**: Share work-in-progress with colleagues \n✅ **Compliance**: Meet regulatory requirements for data disclosure\n\n### User/Data Flow\n\n```mermaid\nflowchart LR\n Profile[(User Profile Data)] --> Filter{Visibility Filter}\n Filter -->|Public Tag| Public[Public Portfolio]\n Filter -->|Team Tag| Internal[Team Dashboard]\n Filter -->|Private Tag| Personal[Personal View Only]\n \n Public --> WebPage[Public Web Page]\n Internal --> TeamDash[Team Dashboard]\n Personal --> UserDash[User Admin Panel]\n \n WebPage --> Visitor([External Visitors])\n TeamDash --> Colleagues([Team Members])\n UserDash --> Owner([Profile Owner])\n \n style Profile fill:#3b82f6,stroke:#2563eb,color:#fff\n style Public fill:#10b981,stroke:#059669,color:#fff\n style Internal fill:#f59e0b,stroke:#d97706,color:#000\n style Personal fill:#ef4444,stroke:#dc2626,color:#fff\n```\n\n---\n\n## Rich Personal Sections Rendering\n\n### Description\n\nComprehensive profile sections covering all aspects of professional and personal identity:\n\n- **Experiences**: Work history with detailed descriptions, technologies used, and achievements\n- **Education**: Academic background with degrees, institutions, and graduation dates\n- **Skills**: Proficiency levels, years of experience, and skill categories\n- **Hobbies**: Personal interests and activities\n- **Domains**: Areas of expertise and specialization\n- **Custom Sections**: Flexible schema for additional content\n\n### User Benefits\n\n✅ **Holistic Profiles**: Capture the complete picture of team members \n✅ **Timeline Visualization**: Experience and education timelines \n✅ **Skill Matrices**: Visual representation of team capabilities \n✅ **Multimedia Support**: Images, videos, documents in sections\n\n### User/Data Flow\n\n```mermaid\nflowchart TB\n Input([User Creates Section]) --> Type{Section Type}\n \n Type -->|Experience| ExpForm[Experience Form]\n Type -->|Education| EduForm[Education Form]\n Type -->|Skill| SkillForm[Skill Form]\n Type -->|Hobby| HobbyForm[Hobby Form]\n Type -->|Domain| DomainForm[Domain Form]\n \n ExpForm --> Validate[Validate Data]\n EduForm --> Validate\n SkillForm --> Validate\n HobbyForm --> Validate\n DomainForm --> Validate\n \n Validate --> Save[(Save to Database)]\n Save --> Render[Render in Profile]\n Render --> Timeline[Generate Timeline]\n Timeline --> Display[Display to Viewers]\n \n style Input fill:#10b981,stroke:#059669,color:#fff\n style Validate fill:#f59e0b,stroke:#d97706,color:#000\n style Save fill:#3b82f6,stroke:#2563eb,color:#fff\n style Display fill:#8b5cf6,stroke:#7c3aed,color:#fff\n```\n\n---\n\n## Technology & Skills Display\n\n### Description\n\nTechnology stack and skills visualization with:\n\n- Technology badges organized by category (Frontend, Backend, Database, Cloud, etc.)\n- Proficiency indicators (Beginner, Intermediate, Advanced, Expert)\n- Years of experience tracking\n- Skill matrices showing team capabilities\n- Technology detail modals with descriptions and links\n\n### User Benefits\n\n✅ **Team Capabilities**: Understand collective technical expertise \n✅ **Project Staffing**: Match skills to project requirements \n✅ **Skill Development**: Identify learning opportunities and gaps \n✅ **Client Communication**: Showcase team expertise to stakeholders\n\n### User/Data Flow\n\n```mermaid\nflowchart TD\n AddSkill([Add Technology/Skill]) --> Details[Enter Details]\n Details --> Category{Select Category}\n \n Category -->|Frontend| FE[React, Next.js, etc.]\n Category -->|Backend| BE[Node.js, Python, etc.]\n Category -->|Database| DB[PostgreSQL, MongoDB, etc.]\n Category -->|Cloud| Cloud[AWS, Azure, GCP]\n \n FE --> Proficiency[Set Proficiency Level]\n BE --> Proficiency\n DB --> Proficiency\n Cloud --> Proficiency\n \n Proficiency --> Years[Years of Experience]\n Years --> Badge[Generate Badge]\n Badge --> Matrix[Add to Skill Matrix]\n Matrix --> TeamView[Display in Team View]\n \n style AddSkill fill:#10b981,stroke:#059669,color:#fff\n style Badge fill:#3b82f6,stroke:#2563eb,color:#fff\n style TeamView fill:#8b5cf6,stroke:#7c3aed,color:#fff\n```"
+ },
+ {
+ "title": "Architecture & Technology",
+ "type": "ARCHITECTURE",
+ "navOrder": 3,
+ "content": "## Architecture Overview\n\n### Technology Stack\n\n**Frontend**\n- **Next.js 15+**: App Router with Server Components, partial prerendering, and advanced caching\n- **React 19**: Latest React features with Suspense and concurrent rendering\n- **TypeScript 5.x**: Strict mode for compile-time type safety\n- **Tailwind CSS**: Utility-first styling framework\n- **Shadcn UI**: Component library built on Radix UI primitives\n\n**Backend**\n- **Next.js API Routes**: Server-side API endpoints with edge runtime support\n- **Prisma ORM**: Type-safe database access with schema-first design\n- **PostgreSQL**: Production-grade relational database\n- **AI Services**:\n - OpenAI GPT-4 for general content generation\n - Anthropic Claude 3 for long-form content\n - Google Gemini 1.5 for multi-modal processing\n\n**Testing & Quality**\n- **Jest**: Unit and integration testing\n- **Playwright**: End-to-end browser testing\n- **TypeScript**: Compile-time type checking\n- **ESLint**: Code quality enforcement\n\n### System Architecture\n\n```mermaid\ngraph TB\n subgraph Client[\"🖥️ Client Layer\"]\n Browser[\"Next.js App Router
Server Components
Client Components
Tailwind + Shadcn UI\"]\n end\n \n subgraph Server[\"⚙️ Server Layer\"]\n API[\"Next.js API Routes
Edge Runtime
Middleware\"]\n Services[\"Business Services
Profile, Team, Task
AI Orchestration\"]\n end\n \n subgraph Data[\"💾 Data Layer\"]\n Prisma[\"Prisma ORM
Type-Safe Queries
Migrations\"]\n DB[(\"PostgreSQL
Relational Data
Transactions\")]\n end\n \n subgraph External[\"🌐 External Services\"]\n OpenAI[\"OpenAI
GPT-4\"]\n Anthropic[\"Anthropic
Claude 3\"]\n Gemini[\"Google
Gemini 1.5\"]\n end\n \n Browser -->|\"SSR/RSC\"| API\n API --> Services\n Services --> Prisma\n Prisma --> DB\n Services -.->|\"AI Requests\"| OpenAI\n Services -.->|\"AI Requests\"| Anthropic\n Services -.->|\"AI Requests\"| Gemini\n \n style Client fill:#1e293b,stroke:#3b82f6,stroke-width:3px,color:#fff\n style Server fill:#1e293b,stroke:#10b981,stroke-width:3px,color:#fff\n style Data fill:#1e293b,stroke:#8b5cf6,stroke-width:3px,color:#fff\n style External fill:#1e293b,stroke:#f59e0b,stroke-width:2px,color:#fff\n```\n\n### Core Entities\n\n```mermaid\nerDiagram\n USER ||--o{ COLLABORATOR : \"has profile\"\n USER {\n uuid id PK\n string username UK\n string password\n string email\n datetime createdAt\n }\n \n COLLABORATOR ||--|{ RESUME_SECTION : \"contains\"\n COLLABORATOR ||--o{ TASK : \"assigned\"\n COLLABORATOR {\n uuid id PK\n uuid userId FK\n string firstName\n string lastName\n string title\n string bio\n string avatarUrl\n boolean isPublic\n }\n \n RESUME_SECTION ||--o{ EXPERIENCE : \"includes\"\n RESUME_SECTION ||--o{ EDUCATION : \"includes\"\n RESUME_SECTION ||--o{ SKILL : \"includes\"\n RESUME_SECTION {\n uuid id PK\n uuid collaboratorId FK\n string sectionType\n boolean isPublic\n json data\n }\n \n EXPERIENCE {\n uuid id PK\n string company\n string role\n date startDate\n date endDate\n text description\n json technologies\n }\n \n EDUCATION {\n uuid id PK\n string institution\n string degree\n string field\n date graduationDate\n }\n \n SKILL ||--|| SKILL_CATEGORY : \"belongs to\"\n SKILL {\n uuid id PK\n string name\n int proficiency\n int yearsOfExperience\n }\n \n SKILL_CATEGORY {\n uuid id PK\n string name UK\n string description\n }\n \n TASK {\n uuid id PK\n uuid collaboratorId FK\n string title\n text description\n string status\n text lessonLearned\n datetime completedAt\n }\n \n PROMPT_TEMPLATE {\n uuid id PK\n string name UK\n string purpose\n text template\n json parameters\n }\n```\n\n---\n\n## Reliability, Solidity, Scalability\n\n### Reliability\n\n**Type Safety**\n- End-to-end TypeScript with strict mode enabled\n- Prisma-generated types ensure database schema matches code\n- Zod schema validation for runtime type checking\n- No `any` types in production code\n\n**Error Handling**\n- Comprehensive try-catch blocks in all async operations\n- Prisma transaction rollback on failures\n- User-friendly error messages with detailed logging\n- Graceful degradation when AI services are unavailable\n\n**Data Integrity**\n- Prisma transactions for multi-step database operations\n- Foreign key constraints enforce referential integrity\n- Soft deletes for critical data (users, profiles)\n- Automated database backups\n\n### Solidity\n\n**Clean Architecture**\n- **Presentation Layer**: Next.js components (Server + Client)\n- **Business Logic Layer**: Service classes isolated from framework\n- **Data Access Layer**: Prisma repositories with abstraction\n- **Shared Layer**: DTOs, types, and utilities\n\n**Design Principles**\n- **Single Responsibility**: Each service handles one domain\n- **Dependency Inversion**: Services depend on interfaces, not implementations\n- **DRY (Don't Repeat Yourself)**: Shared utilities and components\n- **KISS (Keep It Simple)**: Avoid over-engineering\n\n**Testing Strategy**\n- Unit tests for business logic (Jest)\n- Integration tests for API routes\n- E2E tests for critical user flows (Playwright)\n- Continuous testing in CI/CD pipeline\n\n### Scalability\n\n**Next.js 15 Features**\n- **Server Components**: Reduced client-side JavaScript bundle\n- **Partial Prerendering (PPR)**: Static shell with dynamic content\n- **Advanced Caching**: Aggressive caching with revalidation strategies\n- **Edge Runtime**: Deploy API routes to edge for low latency\n\n**Database Optimization**\n- Indexed foreign keys for fast joins\n- Query optimization with Prisma `include` and `select`\n- Connection pooling for concurrent requests\n- Read replicas for scaling read-heavy workloads\n\n**Performance**\n- Image optimization with Next.js `Image` component\n- Code splitting and lazy loading\n- Suspense boundaries for progressive rendering\n- CDN integration for static assets"
+ },
+ {
+ "title": "Development & Quality Assurance",
+ "type": "TECHNICAL",
+ "navOrder": 4,
+ "content": "## Development Lifecycle & Quality Assurance\n\n### Development Cycle\n\nOur development follows an iterative, quality-first approach:\n\n```mermaid\nflowchart LR\n Plan([Feature Planning]) --> Design[System Design]\n Design --> Implement[Implementation]\n Implement --> Test[Testing]\n Test --> Review{Code Review}\n Review -->|Changes Needed| Implement\n Review -->|Approved| Deploy[Deployment]\n Deploy --> Monitor[Monitoring]\n Monitor --> Feedback[Gather Feedback]\n Feedback --> Plan\n \n style Plan fill:#10b981,stroke:#059669,color:#fff\n style Test fill:#f59e0b,stroke:#d97706,color:#000\n style Deploy fill:#3b82f6,stroke:#2563eb,color:#fff\n style Monitor fill:#8b5cf6,stroke:#7c3aed,color:#fff\n```\n\n**Phase 1: Feature Planning**\n- Collaborate with stakeholders to define requirements\n- Create user stories and acceptance criteria\n- Estimate effort and prioritize in backlog\n- Write technical design document if needed\n\n**Phase 2: System Design**\n- Design database schema changes (Prisma migrations)\n- Plan API contracts and DTOs\n- Sketch UI wireframes and component hierarchy\n- Identify dependencies and integration points\n\n**Phase 3: Implementation**\n- Create feature branch from `develop`\n- Write code following style guidelines (ESLint)\n- Implement business logic in services\n- Build UI components with Tailwind + Shadcn\n- Add inline documentation and JSDoc comments\n\n**Phase 4: Testing**\n- Write unit tests for business logic (Jest)\n- Create integration tests for API routes\n- Add E2E tests for user flows (Playwright)\n- Manual testing in development environment\n- Accessibility testing (keyboard navigation, screen readers)\n\n**Phase 5: Code Review**\n- Open pull request with detailed description\n- Automated CI checks (build, tests, linting)\n- Peer review for code quality and design\n- Address feedback and iterate\n\n**Phase 6: Deployment**\n- Merge to `develop` branch\n- Deploy to staging environment\n- Run smoke tests and regression tests\n- Merge to `main` and deploy to production\n\n**Phase 7: Monitoring**\n- Monitor error rates and performance metrics\n- Collect user feedback and usage analytics\n- Identify bugs and improvement opportunities\n- Plan next iteration\n\n---\n\n## Testing Strategy\n\n### Unit Testing (Jest)\n\n**Business Logic**\n```typescript\n// Example: Profile Service unit test\ndescribe('ProfileService', () => {\n it('should generate profile from AI description', async () => {\n const service = new ProfileService(mockPrisma, mockAIService);\n const result = await service.generateFromDescription(\n 'Experienced full-stack developer with 5 years in React'\n );\n expect(result).toHaveProperty('title');\n expect(result).toHaveProperty('bio');\n });\n});\n```\n\n**Model Validation**\n```typescript\n// Example: Zod schema validation test\ndescribe('CollaboratorSchema', () => {\n it('should validate valid collaborator data', () => {\n const data = { firstName: 'John', lastName: 'Doe', ... };\n expect(() => CollaboratorSchema.parse(data)).not.toThrow();\n });\n});\n```\n\n### Integration Testing\n\n**API Routes**\n```typescript\n// Example: API route integration test\ndescribe('POST /api/profile', () => {\n it('should create new collaborator profile', async () => {\n const response = await fetch('/api/profile', {\n method: 'POST',\n body: JSON.stringify({ firstName: 'Jane', ... })\n });\n expect(response.status).toBe(201);\n });\n});\n```\n\n**Database Interactions**\n- Prisma client tests with in-memory SQLite\n- Transaction rollback tests\n- Constraint validation tests\n\n### End-to-End Testing (Playwright)\n\n**Critical User Flows**\n```typescript\n// Example: E2E test for profile creation\ntest('User can create profile via AI generation', async ({ page }) => {\n await page.goto('/profile/new');\n await page.fill('[name=\"description\"]', 'Senior engineer...');\n await page.click('button:has-text(\"Generate with AI\")');\n await expect(page.locator('.profile-preview')).toBeVisible();\n});\n```\n\n**Test Coverage**\n- Profile creation and editing\n- Team organigram navigation\n- Task creation with lesson-learned evaluation\n- AI content generation workflows\n- Public/private visibility toggling\n\n### CI/CD Pipeline\n\n**GitHub Actions Workflow**\n\n```yaml\nname: CI/CD Pipeline\non:\n push:\n branches: [main, develop]\n pull_request:\n branches: [main, develop]\n\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n - uses: actions/setup-node@v4\n with:\n node-version: '20'\n - run: npm ci\n - run: npm run build\n - run: npm test\n - run: npm run test:e2e\n```\n\n**Build Steps**:\n1. ✅ Checkout code\n2. ✅ Install dependencies\n3. ✅ Run TypeScript compiler\n4. ✅ Run ESLint\n5. ✅ Execute unit tests (Jest)\n6. ✅ Execute E2E tests (Playwright)\n7. ✅ Build production bundle\n\n**Quality Gates**:\n- All tests must pass (100% pass rate required)\n- No TypeScript errors\n- No ESLint errors (warnings allowed)\n- Build must complete successfully\n\n---\n\n## Best Practices & Philosophy\n\n### Growth Mindset Integration\n\nThe platform is built on **Carol Dweck's Growth Mindset** principles:\n\n> **Fixed Mindset**: \"I can't do this.\" \n> **Growth Mindset**: \"I can't do this *yet*. What can I learn?\"\n\n**Task Evaluation System**\n- Every completed task prompts: \"What did you learn?\"\n- Lessons are categorized: Technical, Process, Collaboration\n- Team knowledge base grows with each task\n- Celebrate effort and learning, not just outcomes\n\n**Human-Centric Design**\n- AI assists but never replaces human decision-making\n- Transparent AI usage (always show when AI is involved)\n- User control over AI suggestions (approve/reject/refine)\n- Inclusive design with accessibility as a priority\n\n### Development Philosophy\n\n**Reliability First**\n- Type safety prevents entire classes of bugs\n- Comprehensive error handling ensures graceful failures\n- Database transactions maintain data integrity\n\n**Solidity Through Architecture**\n- Clean separation of concerns enables maintainability\n- Service layer isolation allows independent testing\n- Shared contracts ensure consistency across layers\n\n**Scalability by Design**\n- Next.js 15 features optimize for performance from day one\n- Database indexing and query optimization built-in\n- Caching strategies reduce server load\n\n**Continuous Improvement**\n- Regular retrospectives to refine processes\n- Automated testing catches regressions early\n- Monitoring and feedback loops drive iteration\n\n---\n\n## Getting Started\n\n### Prerequisites\n- Node.js >= 20.0.0\n- PostgreSQL >= 14\n- npm >= 10.0.0\n\n### Installation\n\n```bash\n# Clone repository\ngit clone https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.StartupCms.AI.git\ncd Ark.Alliance.StartupCms.AI\n\n# Install dependencies\nnpm install\n\n# Set up environment variables\ncp .env.example .env\n# Edit .env with your database URL and AI API keys\n\n# Run database migrations\nnpx prisma migrate dev\n\n# Seed database (optional)\nnpx prisma db seed\n\n# Start development server\nnpm run dev\n```\n\n### Environment Variables\n\n```env\nDATABASE_URL=\"postgresql://user:password@localhost:5432/startupcms\"\nNEXTAUTH_SECRET=\"your-secret-key\"\nNEXTAUTH_URL=\"http://localhost:3000\"\n\n# AI Provider API Keys\nOPENAI_API_KEY=\"sk-...\"\nANTHROPIC_API_KEY=\"sk-ant-...\"\nGOOGLE_AI_API_KEY=\"...\"\n```\n\n### Running Tests\n\n```bash\n# Unit and integration tests\nnpm test\n\n# E2E tests\nnpm run test:e2e\n\n# Coverage report\nnpm run test:coverage\n```\n\n---\n\n**Built with ❤️ by the Ark Alliance Team** \n**© 2026 M2H.IO - Machine-to-Human Excellence**"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-alliance.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-alliance.json
new file mode 100644
index 0000000000000000000000000000000000000000..212b919254b4c980c559cb98fa637ccbbfc4f9b9
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-alliance.json
@@ -0,0 +1,74 @@
+{
+ "title": "Ark.Alliance",
+ "description": "A philosophical movement and technological platform for authentic human recognition. History celebrates winners, yet every success rests on an invisible mountain of failures and forgotten contributions. Ark.Alliance flips the paradigm: value lies in the authenticity of effort, not the glory of outcome. If AI uses OUR collective knowledge to generate BILLIONS in value, we deserve our fair share. This is the moment humanity sends its invoice to AI.",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/Ark.Alliance/Ark_Alliance_Hero.png",
+ "repoUrl": "",
+ "demoUrl": "",
+ "packageUrl": "",
+ "technologies": [
+ "blockchain",
+ "typescript",
+ "react",
+ "nodejs",
+ "ai"
+ ],
+ "features": [
+ {
+ "title": "Universal Recognition",
+ "description": "Every human is recognized as co-owner of the collective cognitive heritage. From childhood to life's twilight, every authentic action contributes to our collective future. Your effort counts.",
+ "icon": "globe"
+ },
+ {
+ "title": "Authenticity Blockchain",
+ "description": "Track contributions via a decentralized authenticity blockchain. Every documented attempt, every sincere effort, is permanently recorded and valued. Authenticity pays better than cheating.",
+ "icon": "link"
+ },
+ {
+ "title": "Smart Contract Redistribution",
+ "description": "Automatically redistribute AI-generated benefits through smart contracts. If Facebook can track every click to sell ads, we can track every contribution to distribute value. Fair retribution for all.",
+ "icon": "code"
+ },
+ {
+ "title": "ARK Token Ecosystem",
+ "description": "Every documented attempt or effort earns ARK tokens. Share an idea, submit an effort, receive your fair share automatically. The Spotify of contribution meets the Instagram of authenticity.",
+ "icon": "coins"
+ },
+ {
+ "title": "DAO Governance",
+ "description": "Decentralized, transparent governance ensures fair reward based on real contribution. Full DAO governance by 2029, with community-driven evolution for a freer, fairer world.",
+ "icon": "users"
+ },
+ {
+ "title": "AI in Service of Humanity",
+ "description": "AI is the ultimate tool for authentic recognition, not our master. It honors every person at every stage of life and preserves challenge and the boundless space of imagination.",
+ "icon": "brain"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark.Alliance: A New Era for Human Recognition\n\n> *\"Honoring the journey, not just the destination. Your failures today are tomorrow's algorithms.\"*\n\n---\n\n### The Problem We're Solving\n\nHistory has always celebrated winners, etching their names into the marble of collective memory. Yet every success rests on an invisible mountain of failures, courageous attempts, and forgotten contributions. These efforts — often dismissed or ignored — are the essential seeds of all human progress.\n\n**Three undeniable truths:**\n\n| Truth | Reality |\n|-------|--------|\n| AI uses OUR collective knowledge | Fact |\n| It generates BILLIONS in value | Fact |\n| We get NOTHING today | Problem |\n\n---\n\n### The Ark.Alliance Solution\n\nArk.Alliance is born from this fundamental truth: **value lies in the authenticity of effort, not the glory of outcome.**\n\nArtificial intelligence gives us a historic opportunity to flip this paradigm. Just as AI learns more from its errors than its successes, we can create a world where:\n\n- ✨ **Authentic failure** is worth more than artificial success\n- 🎯 **Sincere effort** outweighs hollow victory\n- 🌍 **Every human contribution** is recognized and valued\n- 💰 **Shared cognitive heritage** generates fair retribution for all\n- 🔓 **Authenticity** becomes the most rewarding path\n\n> 💡 **\"This is the moment humanity sends its invoice to AI.\"**\n\n---\n\n### What Makes It Different\n\nArk.Alliance is not just technology — it's a philosophical movement that puts humans at the center of progress.\n\nJust as Wikipedia democratized knowledge, Ark.Alliance democratizes recognition:\n\n| Platform | Analogy |\n|----------|--------|\n| 📚 **The Wikipedia of effort** | Every contribution, no matter how modest, enriches a universal, authentic registry |\n| 🎵 **The Spotify of contribution** | Share an idea or effort = automatically receive your fair share |\n| 📸 **The Instagram of authenticity** | No more empty likes: every genuine interaction creates real value |\n\n> 🎭 *\"Imagine a world where your imposter syndrome becomes your retirement fund.\"*\n\n---\n\n### The Promise\n\nImagine a world where:\n\n- ✨ **Every effort counts** — from childhood to life's twilight, every authentic action contributes to our collective future\n- 🌍 **Authenticity is rewarded** — being yourself becomes the most fulfilling path\n- ⚖️ **Justice prevails** — a decentralized, transparent system ensures fair reward based on real contribution\n- 🔓 **Freedom flourishes** — freed from material constraints and prejudice, people explore the infinite potential of their imagination"
+ },
+ {
+ "title": "Manifesto",
+ "type": "FUNCTIONAL",
+ "navOrder": 2,
+ "content": "## The Ark.Alliance Manifesto\n\n---\n\n### Our Vision: Honoring the Journey\n\nAI teaches us a profound lesson: **it advances more through failed iterations than immediate successes.** Every negative prompt, every error, enriches its understanding. This technological reality invites us to transform how we view humanity.\n\nWe believe:\n\n- Every human deserves recognition for their authentic effort\n- Failure is not the opposite of success — it's part of the path\n- Our collective knowledge belongs to all of us\n- AI-generated value should benefit its true creators: humanity\n\n---\n\n### How Ark.Alliance Changes the Game\n\nThe solution unfolds in **3 acts**:\n\n```mermaid\nflowchart LR\n subgraph Act1[\"🌍 Act 1: Recognition\"]\n A1[\"Recognize every human as\\nco-owner of collective\\ncognitive heritage\"]\n end\n \n subgraph Act2[\"🔗 Act 2: Tracking\"]\n A2[\"Track contributions via\\nauthenticity blockchain\"]\n end\n \n subgraph Act3[\"💰 Act 3: Redistribution\"]\n A3[\"Automatically redistribute\\nbenefits through\\nsmart contracts\"]\n end\n \n Act1 --> Act2 --> Act3\n \n style Act1 fill:#1e3a5f,stroke:#3b82f6,color:#fff\n style Act2 fill:#1e3a5f,stroke:#10b981,color:#fff\n style Act3 fill:#1e3a5f,stroke:#f59e0b,color:#fff\n```\n\n> 💡 *\"If Facebook can track every click to sell ads, we can track every contribution to distribute value.\"*\n\n---\n\n### Our Philosophy: AI in Service of Humanity\n\nAI will never be our \"God\" or master. It is the ultimate tool for authentic recognition that:\n\n| Principle | Commitment |\n|-----------|------------|\n| 🙏 **Honor** | Honors every person at every stage of life |\n| 🌈 **Foundation** | Lays the foundations for a freer, fairer, more human world |\n| 🎯 **Preservation** | Preserves challenge and the boundless space of imagination |\n| 🔓 **Expression** | Allows each of us to express our deepest nature without submission |\n\n---\n\n### The Universal Heritage Principle\n\nWe are all inheritors and contributors to human knowledge. Every:\n\n- 💭 **Thought shared** enriches the collective\n- 📝 **Attempt documented** becomes training data\n- 🎨 **Creation made** inspires future works\n- ❌ **Failure learned from** prevents others' missteps\n\nThis heritage generates **billions in AI value today**. Ark.Alliance ensures this value returns to its rightful creators: **all of us**."
+ },
+ {
+ "title": "Applications & FAQ",
+ "type": "TECHNICAL",
+ "navOrder": 3,
+ "content": "## Applications & How It Works\n\n---\n\n### Who Is Ark.Alliance For?\n\n| Audience | What It Means |\n|----------|---------------|\n| 🖥️ **For geeks** | It's Git, but for all humanity |\n| 🎨 **For artists** | Your drafts finally have value |\n| 🤔 **For philosophers** | The free market of authenticity |\n| 🧐 **For skeptics** | Worst case, it doesn't work. Best case, we revolutionize the world |\n| 👤 **For everyone** | You exist = you contribute = you deserve your share |\n\n---\n\n### The \"First 1000\" Pilot Program\n\nThe first 1,000 contributors become **founding members** of the movement:\n\n```mermaid\nflowchart TB\n subgraph Pilot[\"🚀 First 1000 Founders\"]\n P1[\"📄 Document your efforts\"] --> P2[\"🪙 Earn 1 ARK per contribution\"]\n P2 --> P3[\"⏰ First redistribution at 6 months\"]\n P3 --> P4[\"👑 Become founding member\"]\n end\n \n style Pilot fill:#1a1a2e,stroke:#8b5cf6,color:#fff\n```\n\n**Come as you are, with your failures and dreams. That's exactly what we need.**\n\n---\n\n## Common Objections (and Our Responses)\n\nWe know the idea sounds bold. Here are the most frequent objections… and why they make us smile:\n\n### ❓ \"But who will pay?\"\n\nThe same entities already paying: companies that monetize AI. Except this time, part of the profits is redistributed fairly to the humans whose data trained their systems.\n\n---\n\n### ❓ \"This is communism!\"\n\nNo — it's **fair cognitive capitalism**. Everyone remains owner of their own data and efforts. We're not redistributing existing wealth; we're claiming our fair share of *newly generated* AI value.\n\n---\n\n### ❓ \"It's impossible to measure!\"\n\nWe already track your TikTok screen time to the millisecond. We know exactly which videos you watch, skip, and rewatch. **Measuring authentic contribution? Entirely within reach.**\n\n---\n\n### ❓ \"People will cheat!\"\n\nAs if no one cheats today? At Ark.Alliance:\n\n- 🎯 **Authenticity pays better** than cheating\n- 🔗 **Decentralized mechanisms** limit abuse\n- 👥 **Community validation** filters bad actors\n- 📊 **Effort history** builds reputation over time\n\n---\n\n## Join the \"Finally!\" Revolution\n\n> *\"We don't promise to make you rich. We promise to give you justice. And honestly, that's already a lot.\"*\n\n**Ark.Alliance — Because your failures today are tomorrow's algorithms.**"
+ },
+ {
+ "title": "Roadmap",
+ "type": "ROADMAP",
+ "navOrder": 4,
+ "content": "## Ark.Alliance Roadmap\n\nArk.Alliance advances through concrete, transparent, community-driven stages.\n\n---\n\n```mermaid\ntimeline\n title Ark.Alliance Development Timeline\n \n section Phase 0 - Pilot Launch (Jan-Jun 2026)\n January 2026 : Recruitment of \"First 1000\" founders\n March 2026 : Documentation and ARK token allocation\n June 2026 : Symbolic first redistribution\n \n section Phase 1 - Technical Foundations (2026-2027)\n Q3 2026 : Blockchain protocol development\n Q4 2026 : Decentralized contribution registry\n 2027 : Public beta launch\n \n section Phase 2 - Recognition & Retribution (2027-2028)\n 2027 : Automatic redistributions activated\n 2028 : Mobile app and universal wallet\n 2028 : Large-scale community validation\n \n section Phase 3 - Global Adoption (2028-2030)\n 2028 : AI platform interoperability\n 2029 : Full DAO governance\n 2030 : Education, art, research extension\n \n section Phase 4 - Mature Ecosystem (2030+)\n 2030+ : Universal retribution standard\n Future : Public policy integration\n Ongoing : Community-driven evolution\n```\n\n---\n\n### Phase Details\n\n#### 🚀 Phase 0: Pilot Launch (January–June 2026)\n\n| Milestone | Description |\n|-----------|-------------|\n| **Founder Recruitment** | Recruit the \"First 1000\" founding members |\n| **Token Allocation** | Document and allocate initial ARK tokens for authentic efforts |\n| **First Redistribution** | Symbolic first value redistribution at 6 months |\n| **Community Building** | Collect feedback and build core community |\n\n---\n\n#### 🔧 Phase 1: Technical Foundations (2026–2027)\n\n| Milestone | Description |\n|-----------|-------------|\n| **Blockchain Protocol** | Develop the core blockchain and decentralized contribution registry |\n| **Smart Contracts** | Integrate authentic tracking mechanisms and smart contracts |\n| **Partnerships** | Partner with open-source communities and AI platforms |\n| **Public Beta** | Launch public beta for wider testing |\n\n---\n\n#### 💰 Phase 2: Recognition & Retribution (2027–2028)\n\n| Milestone | Description |\n|-----------|-------------|\n| **Auto-Redistribution** | Activate automatic value redistributions |\n| **Community Validation** | Large-scale program with community-based validation |\n| **Mobile & Wallet** | Launch mobile app and universal wallet |\n\n---\n\n#### 🌍 Phase 3: Global Adoption (2028–2030)\n\n| Milestone | Description |\n|-----------|-------------|\n| **AI Interoperability** | Massive opening and interoperability with major AI platforms |\n| **DAO Governance** | Full decentralized autonomous organization governance |\n| **Sector Extension** | Extension to education, art, and research domains |\n\n---\n\n#### 🏛️ Phase 4: Mature Ecosystem (2030+)\n\n| Milestone | Description |\n|-----------|-------------|\n| **Universal Standard** | Universal retribution as global standard |\n| **Public Policy** | Integration into public policy and responsible companies |\n| **Continuous Evolution** | Ongoing evolution guided by the community |\n\n---\n\n> ⚠️ *This roadmap is iterative and will adapt based on feedback from the first contributors.*"
+ }
+ ]
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-portfolio.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-portfolio.json
new file mode 100644
index 0000000000000000000000000000000000000000..853f4d0198f2d41013101ee88d7fe87d313064d1
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/ark-portfolio.json
@@ -0,0 +1,82 @@
+{
+ "title": "Ark.Alliance.Portfolio",
+ "description": "Production-grade portfolio CMS and static site generator with AI-powered content creation. Features 20 TypeORM entities, multi-provider AI integration (OpenAI, Anthropic, Gemini), one-click static export, MVVM architecture, 235+ passing tests, and comprehensive admin dashboard. Built with React 18, TypeScript 5, Express, and TypeORM with end-to-end type safety.",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.Ai/portfolio-hero.png",
+ "repoUrl": "https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.Portfolio",
+ "demoUrl": "",
+ "packageUrl": "",
+ "technologies": [
+ "react",
+ "typescript",
+ "nodejs",
+ "express",
+ "typeorm",
+ "sqlite",
+ "vite",
+ "jest",
+ "rest",
+ "openai",
+ "anthropic",
+ "gemini"
+ ],
+ "features": [
+ {
+ "title": "20-Entity Content Management System",
+ "description": "Comprehensive CMS with TypeORM entities for Profile, Projects (with multi-page documentation), Experiences, Education, Skills, Media Assets, Carousel, Widgets, and more. Full CRUD operations through an intuitive admin dashboard.",
+ "icon": "database"
+ },
+ {
+ "title": "Multi-Provider AI Integration",
+ "description": "Native integration with OpenAI GPT-4, Anthropic Claude 3, and Google Gemini. AES-256 encrypted API key storage, intelligent content generation, summarization, and professional writing enhancement for all CMS entities.",
+ "icon": "brain"
+ },
+ {
+ "title": "One-Click Static Site Export",
+ "description": "Transform your portfolio CMS into a deployable static website with a single click. Generates optimized HTML/CSS/JS bundles ready for GitHub Pages, Netlify, Vercel, or any CDN with zero server costs.",
+ "icon": "download"
+ },
+ {
+ "title": "Clean Three-Tier Architecture",
+ "description": "Enterprise-grade separation with Presentation (React MVVM), Shared Contracts (TypeScript DTOs), and Application (Express + TypeORM) layers. Repository pattern, type-safe APIs, and comprehensive error handling throughout.",
+ "icon": "sitemap"
+ },
+ {
+ "title": "Production-Grade Security",
+ "description": "JWT authentication with bcrypt password hashing (12 rounds), Helmet security headers, CORS protection, rate limiting, and AES-256 encryption for sensitive credentials. Built for deployment from day one.",
+ "icon": "shield-alt"
+ },
+ {
+ "title": "Dynamic Theme System",
+ "description": "Runtime theme switching with no page reload. Built-in Architectural and Aloe Vera themes, plus JSON-based custom theme creation. CSS variable injection enables instant visual transformations.",
+ "icon": "palette"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark.Alliance.Portfolio\n\n**Production-Grade Portfolio CMS & Static Site Generator**\n\nA comprehensive portfolio platform that goes beyond simple showcases. It combines enterprise-grade software practices with AI-powered content generation, full content management capabilities, and one-click static site deployment.\n\n### Perfect For\n\n- 💼 **Professionals** — Showcase work experience and projects with dynamic CMS\n- 🎓 **Academics** — Document research, publications, and teaching\n- 🎨 **Creatives** — Present portfolio work with rich media management\n- 💻 **Engineers** — Demonstrate technical projects with multi-page documentation\n- 🏢 **Agencies** — Manage team portfolios with collaborative features\n\n### Core Capabilities\n\n| Capability | Description |\n|------------|-------------|\n| **Content Management** | 20 TypeORM entities covering all portfolio aspects |\n| **AI Content Creation** | Multi-provider AI (OpenAI, Anthropic, Gemini) |\n| **Static Site Export** | One-click deployment to any static host |\n| **Multi-Page Projects** | Rich documentation with Markdown + Mermaid |\n| **Dynamic Theming** | Runtime theme switching, no reload required |\n| **Media Management** | Upload, organize, and optimize assets |\n| **Type Safety** | End-to-end TypeScript with shared DTOs |\n| **Security** | JWT auth, bcrypt, AES-256, Helmet headers |\n\n### Technology Stack\n\n**Frontend**\n- React 18 with TypeScript 5.x\n- Vite build tool\n- MVVM component architecture\n- React Router for navigation\n- Axios for API communication\n\n**Backend**\n- Node.js 18+ with Express\n- TypeORM for data access\n- SQLite (dev) / PostgreSQL (prod)\n- 16 business services\n- 9 API controllers\n\n**Shared**\n- TypeScript DTOs\n- Shared enumerations\n- Type-safe contracts\n\n**AI Integration**\n- OpenAI GPT-4 & GPT-4 Turbo\n- Anthropic Claude 3 (Opus, Sonnet, Haiku)\n- Google Gemini 1.5 (Pro, Flash)\n\n### Key Statistics\n\n- **20** TypeORM Entities\n- **16** Backend Services \n- **9** API Controllers\n- **235+** Test Cases (100% pass rate)\n- **3** Architecture Layers\n- **3** AI Providers\n\n### Quick Start\n\n```bash\n# Install shared library\ncd Ark.Alliance.StartupCms.Ai.Share\nnpm install && npm run build\n\n# Start backend (port 3085)\ncd ../Ark.Alliance.StartupCms.Ai.Backend\nnpm install && npm run dev\n\n# Start frontend (port 3080)\ncd ../Ark.Alliance.StartupCms.Ai.UI\nnpm install && npm run dev\n```\n\n**Default admin credentials**: `admin` / `admin123`"
+ },
+ {
+ "title": "Architecture & System Design",
+ "type": "ARCHITECTURE",
+ "navOrder": 2,
+ "content": "## System Architecture\n\n### Three-Tier Architecture\n\n```mermaid\ngraph TB\n subgraph Client[\"🖥️ Presentation Layer\"]\n UI[\"Ark.Alliance.StartupCms.Ai.UI
React 18 + TypeScript
MVVM Architecture
Vite Build Tool\"]\n end\n \n subgraph Contracts[\"📦 Shared Contracts\"]\n Share[\"Ark.Alliance.StartupCms.Ai.Share
DTOs + Enums
Type Definitions
End-to-End Type Safety\"]\n end\n \n subgraph Server[\"⚙️ Application Layer\"]\n Backend[\"Ark.Alliance.StartupCms.Ai.Backend
Express REST API
16 Services + 9 Controllers
TypeORM Data Access\"]\n end\n \n subgraph Data[\"💾 Data Layer\"]\n DB[(\"SQLite (Dev)
PostgreSQL (Prod)
20 Entities\")]\n end\n \n subgraph External[\"🌐 External Services\"]\n AI1[\"OpenAI
GPT-4\"]\n AI2[\"Anthropic
Claude 3\"]\n AI3[\"Google
Gemini 1.5\"]\n end\n \n UI -->|\"REST API
(Axios)\"| Backend\n UI -.->|\"Import Types\"| Share\n Backend -.->|\"Import Types\"| Share\n Backend -->|\"TypeORM ORM\"| DB\n Backend -->|\"Encrypted API\"| AI1\n Backend -->|\"Encrypted API\"| AI2\n Backend -->|\"Encrypted API\"| AI3\n \n style Client fill:#1e293b,stroke:#3b82f6,stroke-width:3px,color:#fff\n style Contracts fill:#1e293b,stroke:#10b981,stroke-width:3px,color:#fff\n style Server fill:#1e293b,stroke:#f59e0b,stroke-width:3px,color:#fff\n style Data fill:#1e293b,stroke:#8b5cf6,stroke-width:2px,color:#fff\n style External fill:#1e293b,stroke:#ef4444,stroke-width:2px,color:#fff\n```\n\n### Entity Relationship Model\n\n```mermaid\nerDiagram\n PROFILE ||--o{ USER : \"manages\"\n PROFILE {\n uuid id PK\n string name\n string title\n string summary\n string email\n string phone\n string location\n }\n \n USER ||--o{ PROJECT : \"creates\"\n USER {\n uuid id PK\n string username UK\n string password\n string role\n }\n \n PROJECT ||--|{ PROJECT_PAGE : \"contains\"\n PROJECT ||--|{ PROJECT_FEATURE : \"has\"\n PROJECT ||--|{ PROJECT_TECHNOLOGY : \"uses\"\n PROJECT {\n uuid id PK\n string title\n string description\n string status\n string imageUrl\n string repoUrl\n string demoUrl\n }\n \n PROJECT_PAGE {\n uuid id PK\n string title\n string type\n text content\n int navOrder\n }\n \n PROJECT_FEATURE {\n uuid id PK\n string title\n text description\n string icon\n }\n \n TECHNOLOGY ||--|{ PROJECT_TECHNOLOGY : \"links\"\n TECHNOLOGY {\n uuid id PK\n string name UK\n string category\n string icon\n }\n \n EXPERIENCE ||--|{ SKILL : \"requires\"\n EXPERIENCE {\n uuid id PK\n string company\n string role\n string description\n date startDate\n date endDate\n }\n \n EDUCATION {\n uuid id PK\n string institution\n string degree\n string field\n date graduationDate\n }\n \n SKILL ||--|| SKILL_CATEGORY : \"belongsTo\"\n SKILL {\n uuid id PK\n string name\n int proficiency\n int yearsOfExperience\n }\n \n SKILL_CATEGORY {\n uuid id PK\n string name UK\n string description\n int displayOrder\n }\n \n MEDIA {\n uuid id PK\n string filename\n string mimetype\n string url\n string category\n int fileSize\n }\n \n CAROUSEL_ITEM {\n uuid id PK\n string title\n string subtitle\n string imageUrl\n string linkUrl\n int order\n boolean isActive\n }\n \n AI_SETTINGS {\n uuid id PK\n string provider\n string model\n string encryptedApiKey\n json config\n }\n \n STYLE_CONFIG {\n uuid id PK\n string themeName UK\n json colorPalette\n json typography\n boolean isActive\n }\n```\n\n### Service Architecture\n\n**Backend Services (16 total)**\n\n| Service | Responsibility | Lines of Code |\n|---------|----------------|---------------|\n| `ProfileService` | Profile CRUD operations | ~180 |\n| `ProjectService` | Project management | ~320 |\n| `ExperienceService` | Work history | ~200 |\n| `EducationService` | Academic background | ~180 |\n| `SkillService` | Skill management | ~220 |\n| `MediaService` | Asset upload & management | ~280 |\n| `AiService` | Multi-provider AI integration | ~450 |\n| `ExportService` | Static site generation | ~650 |\n| `AuthService` | JWT authentication | ~240 |\n| `CarouselService` | Homepage carousel | ~160 |\n| `StyleConfigService` | Theme management | ~190 |\n| ...and 5 more | Additional features | ~800 |\n\n**API Controllers (9 total)**\n- Public: Profile, Projects, Resume, Carousel\n- Admin: All entity CRUD, Media Upload, Static Export, AI Generation\n\n### Admin Dashboard\n\n\n\n*Comprehensive admin interface for managing all portfolio content*"
+ },
+ {
+ "title": "Features & Use Cases",
+ "type": "FUNCTIONAL",
+ "navOrder": 3,
+ "content": "## Functional Use Cases\n\n### 1. Portfolio Content Management\n\n**Scenario**: Professional wants to maintain a dynamic portfolio with CMS\n\n**Workflow**:\n1. Admin logs in with JWT authentication\n2. Navigate to Admin Dashboard\n3. Create/update profile information (name, title, summary, contact)\n4. Add work experiences with:\n - Company, role, dates\n - Detailed descriptions\n - Technology tags\n5. Create projects with:\n - Title, description, status\n - Repository and demo URLs\n - Hero images\n6. Add multi-page project documentation\n7. Upload media assets (images, PDFs, videos)\n8. Configure homepage carousel\n9. Publish changes (live update)\n\n**Benefits**:\n- ✅ Centralized content management\n- ✅ Version control through database\n- ✅ Type-safe data structures\n- ✅ Real-time preview\n- ✅ No code deployments needed\n\n\n\n*Manage projects with full CRUD operations and multi-page documentation*\n\n---\n\n### 2. AI-Assisted Content Generation\n\n**Scenario**: User needs professional content for project descriptions\n\n**Workflow**:\n1. Navigate to **AI Settings** in admin panel\n2. Configure AI provider:\n - Choose: OpenAI, Anthropic, or Gemini\n - Select model (GPT-4, Claude 3 Opus, Gemini 1.5 Pro)\n - Enter API key (encrypted with AES-256)\n3. Select content entity (Project, Experience, Skill, etc.)\n4. Write prompt or select template:\n - \"Generate a professional project summary\"\n - \"Create compelling feature descriptions\"\n - \"Write technical documentation\"\n5. Review AI-generated content\n6. Edit and refine as needed\n7. Save to entity\n\n**Supported Operations**:\n- 📝 Content generation from prompts\n- 📄 Text summarization\n- ✨ Professional writing enhancement\n- 📚 Technical documentation assistance\n- 🎯 SEO optimization suggestions\n\n**AI Provider Comparison**:\n\n| Provider | Best For | Models Available |\n|----------|----------|------------------|\n| OpenAI | General purpose, code | GPT-4, GPT-4 Turbo |\n| Anthropic | Long-form content, analysis | Claude 3 Opus, Sonnet, Haiku |\n| Google Gemini | Multi-modal, structured data | Gemini 1.5 Pro, Flash |\n\n---\n\n### 3. Static Website Deployment\n\n**Scenario**: Deploy portfolio to static hosting (zero server costs)\n\n**Workflow**:\n1. Populate all CMS content (profile, projects, experiences)\n2. Configure visual theme (Architectural or Aloe Vera)\n3. Navigate to **Export** → **Static Site** in admin\n4. Click **\"Generate Static Website\"**\n5. System processes:\n - Renders all React components to HTML\n - Bundles CSS with theme variables\n - Optimizes JavaScript bundle\n - Copies media assets\n - Generates sitemap.xml\n - Creates SEO meta tags\n6. Download ZIP file (typically 5-15 MB)\n7. Extract and deploy to:\n - **GitHub Pages**: Push to `gh-pages` branch\n - **Netlify**: Drag-drop ZIP or connect repo\n - **Vercel**: Import from GitHub\n - **AWS S3 + CloudFront**: Upload to S3 bucket\n\n**Advantages**:\n- 💰 Zero server costs\n- 🚀 Infinite scalability via CDN\n- ⚡ Fast loading times (static assets)\n- 🔒 Maximum security (no backend to attack)\n- 🌍 Global CDN distribution\n- 📱 Mobile-optimized responsive design\n\n**Generated Structure**:\n```\nstatic-export.zip\n├── index.html\n├── projects.html\n├── resume.html\n├── assets/\n│ ├── images/\n│ ├── css/\n│ └── js/\n├── sitemap.xml\n└── robots.txt\n```\n\n---\n\n### 4. Dynamic Theming System\n\n**Scenario**: Customize portfolio appearance without code changes\n\n**Workflow**:\n1. Access **StyleConfig** in admin panel\n2. Choose from built-in themes:\n - **Architectural**: Clean, minimalist, structural aesthetic\n - **Aloe Vera**: Organic, nature-inspired, warm tones\n3. Or create custom theme with JSON:\n ```json\n {\n \"colorPalette\": {\n \"primary\": \"#3B82F6\",\n \"secondary\": \"#8B5CF6\",\n \"accent\": \"#F59E0B\"\n },\n \"typography\": {\n \"fontFamily\": \"Inter, sans-serif\",\n \"headingWeight\": 700\n }\n }\n ```\n4. Click **\"Apply Theme\"** (instant, no reload)\n5. Preview changes across all pages\n6. Save configuration to database\n7. Theme persists across user sessions\n\n**Configuration Options**:\n- 🎨 Color palettes (primary, secondary, accent, backgrounds)\n- 🔤 Typography (fonts, sizes, weights, line heights)\n- 📏 Spacing and padding\n- 🖼️ Border styles and radius\n- 🌈 Gradient definitions\n- 🎭 Component-specific overrides\n\n\n\n*Configure homepage carousel with dynamic theming*\n\n---\n\n### 5. Multi-Page Project Documentation\n\n**Scenario**: Create comprehensive technical documentation for projects\n\n**Workflow**:\n1. Create or edit **Project** entity\n2. Navigate to **Project Pages** tab\n3. Add pages with specific types:\n - **OVERVIEW**: Project summary, quick start\n - **FUNCTIONAL**: Feature specifications, use cases\n - **TECHNICAL**: Implementation details, API docs\n - **ARCHITECTURE**: System diagrams (Mermaid support)\n - **ROADMAP**: Future plans, milestones\n4. Write content in Markdown:\n - Headers, lists, tables\n - Code blocks with syntax highlighting\n - **Mermaid diagrams** for architecture\n - Links and images\n5. Set navigation order (drag-and-drop)\n6. Preview rendered output\n7. Publish (available immediately)\n\n**Benefits**:\n- 📖 Professional documentation structure\n- 🔄 Version controlled in database\n- 🔍 Searchable content\n- 🎨 Rich formatting with Markdown\n- 📊 Visual diagrams with Mermaid\n- 🔗 Deep linking to specific sections\n\n\n\n*Manage professional experience with timeline visualization*\n\n---\n\n### 6. Media Asset Management\n\n**Scenario**: Organize and optimize portfolio media\n\n**Workflow**:\n1. Navigate to **Media** in admin panel\n2. Upload files:\n - Images: PNG, JPG, WebP (auto-optimization)\n - Documents: PDF, DOCX\n - Videos: MP4, WebM\n3. Organize with:\n - Categories (Projects, Experiences, General)\n - Tags for searchability\n - Descriptions and alt text\n4. System processes:\n - Thumbnail generation\n - Image optimization\n - CDN-ready URLs\n5. Use media in projects, experiences, or carousel\n6. Track usage and file sizes\n\n**Supported Operations**:\n- 📤 Upload (single or batch)\n- 🗂️ Categorize and tag\n- 🔍 Search and filter\n- 🖼️ Preview and edit metadata\n- 🗑️ Delete with orphan detection\n- 📊 Storage analytics"
+ },
+ {
+ "title": "Deployment & Integration",
+ "type": "TECHNICAL",
+ "navOrder": 4,
+ "content": "## Deployment\n\n### Prerequisites\n\n- Node.js >= 18.0.0\n- npm >= 9.0.0\n- Git for version control\n\n### Development Setup\n\n```bash\n# 1. Clone repository\ngit clone https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.Portfolio.git\ncd Ark.Alliance.Portfolio\n\n# 2. Install and build Shared Library (REQUIRED FIRST)\ncd Ark.Alliance.StartupCms.Ai.Share\nnpm install\nnpm run build\n\n# 3. Install and start Backend\ncd ../Ark.Alliance.StartupCms.Ai.Backend\nnpm install\nnpm run dev\n# Backend runs on https://localhost:3085\n\n# 4. In new terminal - Install and start Frontend\ncd Ark.Alliance.StartupCms.Ai.UI\nnpm install\nnpm run dev\n# Frontend runs on http://localhost:3080\n```\n\n### Production Build\n\n```bash\n# Build all layers\ncd Ark.Alliance.StartupCms.Ai.Share && npm run build\ncd ../Ark.Alliance.StartupCms.Ai.Backend && npm run build\ncd ../Ark.Alliance.StartupCms.Ai.UI && npm run build\n```\n\n### Environment Variables\n\n**Backend** (`Ark.Alliance.StartupCms.Ai.Backend/.env`):\n```env\n# Server Configuration\nPORT=3085\nNODE_ENV=development\n\n# Database\nDATABASE_TYPE=sqlite\nDATABASE_NAME=portfolio.db\n\n# Authentication\nJWT_SECRET=your-super-secret-jwt-key\nJWT_EXPIRES_IN=24h\n\n# AI Services (encrypted in production)\nOPENAI_API_KEY=sk-...\nANTHROPIC_API_KEY=sk-ant-...\nGOOGLE_AI_API_KEY=...\n\n# CORS\nCORS_ORIGIN=http://localhost:3080\n```\n\n**Frontend** (`Ark.Alliance.StartupCms.Ai.UI/.env`):\n```env\n# API Configuration\nVITE_API_URL=https://localhost:3085/api\nVITE_USE_MOCK_DATA=false\n\n# Feature Flags\nVITE_ENABLE_AI_FEATURES=true\nVITE_ENABLE_STATIC_EXPORT=true\n```\n\n---\n\n## Testing\n\n### Running Tests\n\n```bash\ncd Ark.Alliance.StartupCms.Ai.Tests\nnpm install\n\n# Run all tests\nnpm test\n\n# With coverage report\nnpm run test:coverage\n```\n\n**Test Statistics**: 235+ tests with 100% pass rate using Jest and React Testing Library.\n\n---\n\n## CI/CD Pipeline\n\n### GitHub Actions Workflow\n\nTriggered on:\n- **Push** to `main` or `develop` branches\n- **Pull Requests** targeting `main` or `develop`\n\n**Workflow Steps**:\n1. ✅ Build Shared Library\n2. ✅ Build Backend\n3. ✅ Build Frontend\n4. ✅ Run Test Suite (235+ tests)\n\n**Branch Protection**:\n\n| Branch | Protection Rules |\n|--------|-----------------|\n| `main` | Requires PR approval, passing CI, no force push |\n| `develop` | Requires passing CI |\n\n---\n\n## Security\n\n### Security Features\n\n- 🔐 **JWT Authentication**: Token-based auth with bcrypt hashing\n- 🛡️ **Helmet Headers**: Security headers for all responses\n- 🔑 **Encrypted Storage**: AES-256 encryption for AI API keys\n- 🚫 **CORS Protection**: Configurable allowed origins\n- 🔒 **Input Validation**: Class-validator and sanitization\n- 📊 **Rate Limiting**: Prevent abuse and DoS attacks\n\n### Reporting Vulnerabilities\n\nFor security concerns, review [SECURITY.md](https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.Portfolio/blob/main/SECURITY.md) or email: security@ark-alliance.io\n\n---\n\n## Static Site Export\n\n### Export Process\n\n1. Log in to Admin Dashboard\n2. Navigate to **Export** → **Static Site**\n3. Click **Generate Static Website**\n4. Download ZIP file (5-15 MB)\n5. Deploy to:\n - **GitHub Pages**: Push to `gh-pages` branch\n - **Netlify**: Drag-drop or connect repo\n - **Vercel**: Import from GitHub\n - **AWS S3**: Upload to bucket\n\n### Output Structure\n\n```\nstatic-export.zip\n├── index.html # Homepage\n├── projects.html # Projects catalog\n├── resume.html # Professional resume\n├── assets/\n│ ├── images/ # Optimized images\n│ ├── css/ # Bundled styles\n│ └── js/ # Minified JavaScript\n├── sitemap.xml # SEO sitemap\n└── robots.txt # Crawler instructions\n```\n\n---\n\n## Contributing\n\nWe welcome contributions! Please read [CONTRIBUTING.md](https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.Portfolio/blob/main/CONTRIBUTING.md) for guidelines.\n\n### Quick Guide\n\n1. Fork the repository\n2. Create feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit changes (`git commit -m 'Add amazing feature'`)\n4. Push to branch (`git push origin feature/amazing-feature`)\n5. Open Pull Request\n\n---\n\n## License\n\nThis project is licensed under the **MIT License** - see [LICENSE.md](https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.Portfolio/blob/main/LICENSE.md) for details.\n\n**Built with ❤️ by Armand Richelet-Kleinberg | © M2H.IO - Ark Alliance Ecosystem**"
+ }
+ ]
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/carousel-ark-portfolio.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/carousel-ark-portfolio.json
new file mode 100644
index 0000000000000000000000000000000000000000..93275f96ba762aa00d323ecfad60156dfa659010
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/carousel-ark-portfolio.json
@@ -0,0 +1,48 @@
+[
+ {
+ "title": "Ark.Alliance.Portfolio",
+ "subtitle": "AI-Powered Portfolio CMS & Static Site Generator",
+ "description": "Production-grade content management system for portfolios with multi-provider AI integration, one-click static export, and comprehensive admin dashboard.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.Ai/portfolio-hero.png",
+ "linkUrl": "/projects/ark-alliance-portfolio",
+ "order": 1,
+ "isActive": true
+ },
+ {
+ "title": "Admin Dashboard",
+ "subtitle": "Comprehensive Content Management Interface",
+ "description": "Manage all portfolio content through an intuitive admin interface with real-time preview and AI-assisted content creation.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.Ai/Admin_Dashobard.PNG",
+ "linkUrl": "/admin/dashboard",
+ "order": 2,
+ "isActive": true
+ },
+ {
+ "title": "Project Management",
+ "subtitle": "Multi-Page Documentation System",
+ "description": "Create rich project documentation with Markdown support, Mermaid diagrams, and comprehensive feature descriptions.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.Ai/Admin_Projects.PNG",
+ "linkUrl": "/admin/projects",
+ "order": 3,
+ "isActive": true
+ },
+ {
+ "title": "Homepage Carousel",
+ "subtitle": "Dynamic Homepage Content",
+ "description": "Configure eye-catching carousel items with custom images, titles, and links to highlight your best work.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.Ai/Admin_Hero_Carrousel.PNG",
+ "linkUrl": "/admin/carousel",
+ "order": 4,
+ "isActive": true
+ },
+ {
+ "title": "Resume Builder",
+ "subtitle": "Professional Experience Timeline",
+ "description": "Build your professional story with rich experience entries, education history, and skill management.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.Ai/Admin_ResumeManager.PNG",
+ "linkUrl": "/admin/resume",
+ "order": 5,
+ "isActive": true
+ }
+]
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/carousel-react-component.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/carousel-react-component.json
new file mode 100644
index 0000000000000000000000000000000000000000..7e4337a7a904dccabd0de92ece6b103f93c13d9a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/carousel-react-component.json
@@ -0,0 +1,11 @@
+[
+ {
+ "title": "Ark.Alliance.React.Component.UI",
+ "subtitle": "Enterprise MVVM Component Library",
+ "description": "Production-grade React components with strict MVVM architecture, Zod validation, and 100% test coverage. 40 categories for Finance, Healthcare, E-Commerce, and more.",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.React.Component/components-hero.png",
+ "linkUrl": "/projects/ark-alliance-react-component-ui",
+ "order": 1,
+ "isActive": true
+ }
+]
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/projects.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/projects.json
new file mode 100644
index 0000000000000000000000000000000000000000..429d2d26e29cf2a8856f9bb08d34179838c30383
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/projects.json
@@ -0,0 +1,248 @@
+[
+ {
+ "title": "Ark.Alliance.Portfolio",
+ "description": "Production-grade portfolio CMS and static site generator with AI-powered content creation. Features 20 TypeORM entities, multi-provider AI integration (OpenAI, Anthropic, Gemini), one-click static export, MVVM architecture, 235+ passing tests, and comprehensive admin dashboard. Built with React 18, TypeScript, Express, and TypeORM with end-to-end type safety.",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.StartupCms.Ai/portfolio-hero.png",
+ "repoUrl": "https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.Portfolio",
+ "demoUrl": "",
+ "packageUrl": "",
+ "technologies": [
+ "react",
+ "typescript",
+ "nodejs",
+ "express",
+ "typeorm",
+ "sqlite",
+ "vite",
+ "jest",
+ "rest",
+ "openai",
+ "anthropic",
+ "gemini"
+ ],
+ "features": [
+ {
+ "title": "20-Entity Content Management System",
+ "description": "Comprehensive CMS with TypeORM entities for Profile, Projects (with multi-page documentation), Experiences, Education, Skills, Media Assets, Carousel, Widgets, and more. Full CRUD operations through an intuitive admin dashboard.",
+ "icon": "database"
+ },
+ {
+ "title": "Multi-Provider AI Integration",
+ "description": "Native integration with OpenAI GPT-4, Anthropic Claude 3, and Google Gemini. AES-256 encrypted API key storage, intelligent content generation, summarization, and professional writing enhancement for all CMS entities.",
+ "icon": "brain"
+ },
+ {
+ "title": "One-Click Static Site Export",
+ "description": "Transform your portfolio CMS into a deployable static website with a single click. Generates optimized HTML/CSS/JS bundles ready for GitHub Pages, Netlify, Vercel, or any CDN with zero server costs.",
+ "icon": "download"
+ },
+ {
+ "title": "Clean Three-Tier Architecture",
+ "description": "Enterprise-grade separation with Presentation (React MVVM), Shared Contracts (TypeScript DTOs), and Application (Express + TypeORM) layers. Repository pattern, type-safe APIs, and comprehensive error handling throughout.",
+ "icon": "sitemap"
+ },
+ {
+ "title": "Production-Grade Security",
+ "description": "JWT authentication with bcrypt password hashing (12 rounds), Helmet security headers, CORS protection, rate limiting, and AES-256 encryption for sensitive credentials. Built for deployment from day one.",
+ "icon": "shield-alt"
+ },
+ {
+ "title": "Dynamic Theme System",
+ "description": "Runtime theme switching with no page reload. Built-in Architectural and Aloe Vera themes, plus JSON-based custom theme creation. CSS variable injection enables instant visual transformations.",
+ "icon": "palette"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark.Alliance.Portfolio\n\n**Production-Grade Portfolio CMS & Static Site Generator**\n\nA comprehensive portfolio platform that goes beyond simple showcases. It combines enterprise-grade software practices with AI-powered content generation, full content management capabilities, and one-click static site deployment.\n\n### Perfect For\n\n- 💼 **Professionals** — Showcase work experience and projects with dynamic CMS\n- 🎓 **Academics** — Document research, publications, and teaching\n- 🎨 **Creatives** — Present portfolio work with rich media management\n- 💻 **Engineers** — Demonstrate technical projects with multi-page documentation\n- 🏢 **Agencies** — Manage team portfolios with collaborative features\n\n### Core Capabilities\n\n| Capability | Description |\n|------------|-------------|\n| **Content Management** | 20 TypeORM entities covering all portfolio aspects |\n| **AI Content Creation** | Multi-provider AI (OpenAI, Anthropic, Gemini) |\n| **Static Site Export** | One-click deployment to any static host |\n| **Multi-Page Projects** | Rich documentation with Markdown + Mermaid |\n| **Dynamic Theming** | Runtime theme switching, no reload required |\n| **Media Management** | Upload, organize, and optimize assets |\
+| **Type Safety** | End-to-end TypeScript with shared DTOs |\n| **Security** | JWT auth, bcrypt, AES-256, Helmet headers |\n\n### Technology Stack\n\n**Frontend**\n- React 18 with TypeScript 5.x\n- Vite build tool\n- MVVM component architecture\n- React Router for navigation\n- Axios for API communication\n\n**Backend**\n- Node.js 18+ with Express\n- TypeORM for data access\n- SQLite (dev) / PostgreSQL (prod)\n- 16 business services\n- 9 API controllers\n\n**Shared**\n- TypeScript DTOs\n- Shared enumerations\n- Type-safe contracts\n\n**AI Integration**\n- OpenAI GPT-4 & GPT-4 Turbo\n- Anthropic Claude 3 (Opus, Sonnet, Haiku)\n- Google Gemini 1.5 (Pro, Flash)\n\n### Key Statistics\n\n- **20** TypeORM Entities\n- **16** Backend Services \n- **9** API Controllers\n- **235+** Test Cases (100% pass rate)\n- **3** Architecture Layers\n- **3** AI Providers\n\n### Quick Start\n\n```bash\n# Install shared library\ncd Ark.Alliance.StartupCms.Ai.Share\nnpm install && npm run build\n\n# Start backend (port 3085)\ncd ../Ark.Alliance.StartupCms.Ai.Backend\nnpm install && npm run dev\n\n# Start frontend (port 3080)\ncd ../Ark.Alliance.StartupCms.Ai.UI\nnpm install && npm run dev\n```\n\nDefault admin credentials: `admin` / `admin123`"
+ },
+ {
+ "title": "Architecture & System Design",
+ "type": "ARCHITECTURE",
+ "navOrder": 2,
+ "content": "## System Architecture\n\n### Three-Tier Architecture\n\n```mermaid\ngraph TB\n subgraph Client[\"🖥️ Presentation Layer\"]\n UI[\"Ark.Alliance.StartupCms.Ai.UI
React 18 + TypeScript
MVVM Architecture
Vite Build Tool\"]\n end\n \n subgraph Contracts[\"📦 Shared Contracts\"]\n Share[\"Ark.Alliance.StartupCms.Ai.Share
DTOs + Enums
Type Definitions
End-to-End Type Safety\"]\n end\n \n subgraph Server[\"⚙️ Application Layer\"]\n Backend[\"Ark.Alliance.StartupCms.Ai.Backend
Express REST API
16 Services + 9 Controllers
TypeORM Data Access\"]\n end\n \n subgraph Data[\"💾 Data Layer\"]\n DB[(\"SQLite (Dev)
PostgreSQL (Prod)
20 Entities\")]\n end\n \n subgraph External[\"🌐 External Services\"]\
+ AI1[\"OpenAI
GPT-4\"]\
+ AI2[\"Anthropic
Claude 3\"]\
+ AI3[\"Google
Gemini 1.5\"]\
+ end\
+ \
+ UI -->|\"REST API
(Axios)\"| Backend\
+ UI -.->|\"Import Types\"| Share\
+ Backend -.->|\"Import Types\"| Share\
+ Backend -->|\"TypeORM ORM\"| DB\
+ Backend -->|\"Encrypted API\"| AI1\
+ Backend -->|\"Encrypted API\"| AI2\
+ Backend -->|\"Encrypted API\"| AI3\
+ \
+ style Client fill:#2d3748,stroke:#4299e1,stroke-width: 2px,color:#fff\
+ style Contracts fill:#2d3748,stroke:#48bb78,stroke-width: 2px,color:#fff\
+ style Server fill:#2d3748,stroke:#ed8936,stroke-width: 2px,color:#fff\
+ style Data fill:#2d3748,stroke:#9f7aea,stroke-width: 2px,color:#fff\
+ style External fill:#2d3748,stroke:#f56565,stroke-width: 2px,color:#fff\
+```\n\n### Entity Relationship Model\n\n```mermaid\nerDiagram\n PROFILE ||--o{ USER : \"manages\"\n PROFILE {\n uuid id PK\n string name\n string title\n string summary\n string email\n string phone\n string location\n }\n \n USER ||--o{ PROJECT : \"creates\"\n USER {\n uuid id PK\n string username UK\n string password\n string role\n }\n \n PROJECT ||--|{ PROJECT_PAGE : \"contains\"\n PROJECT ||--|{ PROJECT_FEATURE : \"has\"\n PROJECT ||--|{ PROJECT_TECHNOLOGY : \"uses\"\n PROJECT {\n uuid id PK\n string title\n string description\n string status\n string imageUrl\n string repoUrl\n string demoUrl\n }\n \n PROJECT_PAGE {\n uuid id PK\n string title\n string type\n text content\n int navOrder\n }\n \n PROJECT_FEATURE {\n uuid id PK\n string title\n text description\n string icon\n }\n \n TECHNOLOGY ||--|{ PROJECT_TECHNOLOGY : \"links\"\n TECHNOLOGY {\n uuid id PK\n string name UK\n string category\n string icon\n }\n \n EXPERIENCE ||--|{ SKILL : \"requires\"\n EXPERIENCE {\n uuid id PK\n string company\n string role\n string description\n date startDate\n date endDate\n }\n \n EDUCATION {\n uuid id PK\n string institution\n string degree\n string field\n date graduationDate\n }\n \n SKILL ||--|| SKILL_CATEGORY : \"belongsTo\"\n SKILL {\n uuid id PK\n string name\n int proficiency\n int yearsOfExperience\n }\n \n SKILL_CATEGORY {\n uuid id PK\n string name UK\n string description\n int displayOrder\n }\n \n MEDIA {\n uuid id PK\n string filename\n string mimetype\n string url\n string category\n int fileSize\n }\n \n CAROUSEL_ITEM {\n uuid id PK\n string title\n string subtitle\n string imageUrl\n string linkUrl\n int order\n boolean isActive\n }\n \n AI_SETTINGS {\n uuid id PK\n string provider\n string model\n string encryptedApiKey\n json config\n }\n \n STYLE_CONFIG {\n uuid id PK\n string themeName UK\n json colorPalette\n json typography\n boolean isActive\n }\n```\n\n### Service Architecture\n\n**Backend Services (16 total)**\n\n| Service | Responsibility | Lines of Code |\n|---------|----------------|---------------|\n| `ProfileService` | Profile CRUD operations | ~180 |\n| `ProjectService` | Project management | ~320 |\n| `ExperienceService` | Work history | ~200 |\n| `EducationService` | Academic background | ~180 |\n| `SkillService` | Skill management | ~220 |\n| `MediaService` | Asset upload & management | ~280 |\n| `AiService` | Multi-provider AI integration | ~450 |\n| `ExportService` | Static site generation | ~650 |\n| `AuthService` | JWT authentication | ~240 |\n| `CarouselService` | Homepage carousel | ~160 |\n| `StyleConfigService` | Theme management | ~190 |\n| ...and 5 more | Additional features | ~800 |\n\n**API Controllers (9 total)**\n- Public: Profile, Projects, Resume, Carousel\n- Admin: All entity CRUD, Media Upload, Static Export, AI Generation\n\n### Admin Dashboard\n\n\n\n*Comprehensive admin interface for managing all portfolio content*"
+ },
+ {
+ "title": "Features & Use Cases",
+ "type": "FUNCTIONAL",
+ "navOrder": 3,
+ "content": "## Functional Use Cases\n\n### 1. Portfolio Content Management\n\n**Scenario**: Professional wants to maintain a dynamic portfolio with CMS\n\n**Workflow**:\n1. Admin logs in with JWT authentication\n2. Navigate to Admin Dashboard\n3. Create/update profile information (name, title, summary, contact)\n4. Add work experiences with:\n - Company, role, dates\n - Detailed descriptions\n - Technology tags\n5. Create projects with:\n - Title, description, status\n - Repository and demo URLs\n - Hero images\n6. Add multi-page project documentation\n7. Upload media assets (images, PDFs, videos)\n8. Configure homepage carousel\n9. Publish changes (live update)\n\n**Benefits**:\n- ✅ Centralized content management\n- ✅ Version control through database\n- ✅ Type-safe data structures\n- ✅ Real-time preview\n- ✅ No code deployments needed\n\n\n\n*Manage projects with full CRUD operations and multi-page documentation*\n\n---\n\n### 2. AI-Assisted Content Generation\n\n**Scenario**: User needs professional content for project descriptions\n\n**Workflow**:\n1. Navigate to **AI Settings** in admin panel\n2. Configure AI provider:\n - Choose: OpenAI, Anthropic, or Gemini\n - Select model (GPT-4, Claude 3 Opus, Gemini 1.5 Pro)\n - Enter API key (encrypted with AES-256)\n3. Select content entity (Project, Experience, Skill, etc.)\n4. Write prompt or select template:\n - \"Generate a professional project summary\"\n - \"Create compelling feature descriptions\"\n - \"Write technical documentation\"\n5. Review AI-generated content\n6. Edit and refine as needed\n7. Save to entity\n\n**Supported Operations**:\n- 📝 Content generation from prompts\n- 📄 Text summarization\n- ✨ Professional writing enhancement\n- 📚 Technical documentation assistance\n- 🎯 SEO optimization suggestions\n\n**AI Provider Comparison**:\n\n| Provider | Best For | Models Available |\n|----------|----------|------------------|\n| OpenAI | General purpose, code | GPT-4, GPT-4 Turbo |\n| Anthropic | Long-form content, analysis | Claude 3 Opus, Sonnet, Haiku |\n| Google Gemini | Multi-modal, structured data | Gemini 1.5 Pro, Flash |\n\n---\n\n### 3. Static Website Deployment\n\n**Scenario**: Deploy portfolio to static hosting (zero server costs)\n\n**Workflow**:\n1. Populate all CMS content (profile, projects, experiences)\n2. Configure visual theme (Architectural or Aloe Vera)\n3. Navigate to **Export** → **Static Site** in admin\n4. Click **\"Generate Static Website\"**\n5. System processes:\n - Renders all React components to HTML\n - Bundles CSS with theme variables\n - Optimizes JavaScript bundle\n - Copies media assets\n - Generates sitemap.xml\n - Creates SEO meta tags\n6. Download ZIP file (typically 5-15 MB)\n7. Extract and deploy to:\n - **GitHub Pages**: Push to `gh-pages` branch\n - **Netlify**: Drag-drop ZIP or connect repo\n - **Vercel**: Import from GitHub\n - **AWS S3 + CloudFront**: Upload to S3 bucket\n\n**Advantages**:\n- 💰 Zero server costs\n- 🚀 Infinite scalability via CDN\n- ⚡ Fast loading times (static assets)\n- 🔒 Maximum security (no backend to attack)\n- 🌍 Global CDN distribution\n- 📱 Mobile-optimized responsive design\n\n**Generated Structure**:\n```\nstatic-export.zip\n├── index.html\n├── projects.html\n├── resume.html\n├── assets/\n│ ├── images/\n│ ├── css/\n│ └── js/\n├── sitemap.xml\n└── robots.txt\n```\n\n---\n\n### 4. Dynamic Theming System\n\n**Scenario**: Customize portfolio appearance without code changes\n\n**Workflow**:\n1. Access **StyleConfig** in admin panel\n2. Choose from built-in themes:\n - **Architectural**: Clean, minimalist, structural aesthetic\n - **Aloe Vera**: Organic, nature-inspired, warm tones\n3. Or create custom theme with JSON:\n ```json\n {\n \"colorPalette\": {\n \"primary\": \"#3B82F6\",\n \"secondary\": \"#8B5CF6\",\n \"accent\": \"#F59E0B\"\n },\n \"typography\": {\n \"fontFamily\": \"Inter, sans-serif\",\n \"headingWeight\": 700\n }\n }\n ```\n4. Click **\"Apply Theme\"** (instant, no reload)\n5. Preview changes across all pages\n6. Save configuration to database\n7. Theme persists across user sessions\n\n**Configuration Options**:\n- 🎨 Color palettes (primary, secondary, accent, backgrounds)\n- 🔤 Typography (fonts, sizes, weights, line heights)\n- 📏 Spacing and padding\n- 🖼️ Border styles and radius\n- 🌈 Gradient definitions\n- 🎭 Component-specific overrides\n\n\n\n*Configure homepage carousel with dynamic theming*\n\n---\n\n### 5. Multi-Page Project Documentation\n\n**Scenario**: Create comprehensive technical documentation for projects\n\n**Workflow**:\n1. Create or edit **Project** entity\n2. Navigate to **Project Pages** tab\n3. Add pages with specific types:\n - **OVERVIEW**: Project summary, quick start\n - **FUNCTIONAL**: Feature specifications, use cases\n - **TECHNICAL**: Implementation details, API docs\n - **ARCHITECTURE**: System diagrams (Mermaid support)\n - **ROADMAP**: Future plans, milestones\n4. Write content in Markdown:\n - Headers, lists, tables\n - Code blocks with syntax highlighting\n - **Mermaid diagrams** for architecture\n - Links and images\n5. Set navigation order (drag-and-drop)\n6. Preview rendered output\n7. Publish (available immediately)\n\n**Benefits**:\n- 📖 Professional documentation structure\n- 🔄 Version controlled in database\n- 🔍 Searchable content\n- 🎨 Rich formatting with Markdown\n- 📊 Visual diagrams with Mermaid\n- 🔗 Deep linking to specific sections\n\n\n\n*Manage professional experience with timeline visualization*\n\n---\n\n### 6. Media Asset Management\n\n**Scenario**: Organize and optimize portfolio media\n\n**Workflow**:\n1. Navigate to **Media** in admin panel\n2. Upload files:\n - Images: PNG, JPG, WebP (auto-optimization)\n - Documents: PDF, DOCX\n - Videos: MP4, WebM\n3. Organize with:\n - Categories (Projects, Experiences, General)\n - Tags for searchability\n - Descriptions and alt text\n4. System processes:\n - Thumbnail generation\n - Image optimization\n - CDN-ready URLs\n5. Use media in projects, experiences, or carousel\n6. Track usage and file sizes\n\n**Supported Operations**:\n- 📤 Upload (single or batch)\n- 🗂️ Categorize and tag\n- 🔍 Search and filter\n- 🖼️ Preview and edit metadata\n- 🗑️ Delete with orphan detection\n- 📊 Storage analytics"
+ },
+ {
+ "title": "Deployment & Integration",
+ "type": "TECHNICAL",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/trading-hero.png",
+ "repoUrl": "https://github.com/ArmandRicheletKleinberg/Ark.Alliance.Trading.Providers.Lib",
+ "demoUrl": "",
+ "packageUrl": "https://www.npmjs.com/package/ark-alliance-trading-providers-lib",
+ "technologies": [
+ "typescript",
+ "nodejs",
+ "binance",
+ "deribit",
+ "rest",
+ "jest",
+ "docker"
+ ],
+ "features": [
+ {
+ "title": "Multi-Provider Abstraction",
+ "description": "Unified interface for Binance Futures and Deribit exchanges with IProviderClient pattern. Write once, trade on any supported exchange without code changes. Extensible architecture for adding new providers.",
+ "icon": "plug"
+ },
+ {
+ "title": "Result Pattern Error Handling",
+ "description": "Type-safe Result pattern for functional error handling. No exceptions in normal flow, explicit success/failure states, chainable operations (map, flatMap), and comprehensive error details with ResultStatus enum.",
+ "icon": "check-circle"
+ },
+ {
+ "title": "Real-Time WebSocket Streams",
+ "description": "Low-latency market data via WebSocket connections. Subscribe to klines, book ticker, user data streams, and order events. Event-driven architecture with typed event emitters for order fills and position updates.",
+ "icon": "wifi"
+ },
+ {
+ "title": "Secure Authentication",
+ "description": "HMAC-SHA256 signature generation for Binance, Ed25519 signature generation for Deribit, automatic token refresh mechanisms, and secure credential storage with IAuthStrategy interface.",
+ "icon": "lock"
+ },
+ {
+ "title": "Comprehensive Testing",
+ "description": "70+ test scenarios with ReflectionTestEngine, scenario-driven JSON test definitions, dynamic parameter resolution ($DYNAMIC_LIMIT_BUY), tested against live testnets, and 100% pass rate across all categories.",
+ "icon": "vial"
+ },
+ {
+ "title": "Clean Architecture",
+ "description": "Domain-driven design with clear layer separation: Domain (entities, interfaces), Application (use cases, mappers), and Infrastructure (clients, auth). TypeScript-first with full IntelliSense support.",
+ "icon": "sitemap"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark Alliance Trading Providers Library\n\n**Production-Ready Multi-Provider Cryptocurrency Trading SDK**\n\nA TypeScript SDK that unifies cryptocurrency trading across multiple exchanges with a single, elegant API. Stop writing exchange-specific code—write once, trade everywhere.\n\n### Perfect For\n\n- 🤖 Algorithmic trading bots\n- 📊 Market data aggregators\n- 💼 Portfolio management systems\n- 📈 Trading analytics platforms\n\n### Key Features\n\n| Feature | Description |\n|---------|-------------|\n| **Multi-Provider** | Unified interface for Binance Futures and Deribit |\n| **Order Management** | Place, modify, cancel, and track orders |\n| **Position Tracking** | Real-time position monitoring with P&L |\n| **WebSocket Streams** | Low-latency market data and user events |\n| **Event-Driven** | Async event architecture for fills, updates |\n| **Result Pattern** | Type-safe error handling|\n| **Secure Auth** | HMAC-SHA256 (Binance) and Ed25519 (Deribit) |\n| **100% Tested** | 70+ scenarios, 100% pass rate |\n| **TypeScript-First** | Full type definitions with IntelliSense |\n| **Testnet Support** | Built-in testnet URLs for development |\n\n### Installation\n\n```bash\nnpm install ark-alliance-trading-providers-lib\n```\n\n### Quick Start\n\n```typescript\nimport { BinanceRestClient } from 'ark-alliance-trading-providers-lib/Binance';\n\n// Initialize client\nconst client = new BinanceRestClient(apiKey, secret, { testnet: true });\n\n// Place order with type-safe Result pattern\nconst orderResult = await client.placeOrder({\n symbol: 'BTCUSDT',\n side: 'BUY',\n type: 'MARKET',\n quantity: 0.001\n});\n\nif (orderResult.success) {\n console.log(`Order placed! ID: ${orderResult.data.orderId}`);\n} else {\n console.error(`Error: ${orderResult.error.message}`);\n}\n```"
+ },
+ {
+ "title": "Architecture",
+ "type": "ARCHITECTURE",
+ "navOrder": 2,
+ "content": "## Clean Architecture\n\n### Layer Structure\n\n```\nDomain Layer\n├── Domain Entities (Order, Position, Account)\n└── Interfaces (IProviderClient, IAuthStrategy)\n ↓\nApplication Layer\n├── Use Cases (Place Order, Get Position)\n└── Data Mappers (API ↔ Domain)\n ↓\nInfrastructure Layer\n├── API Clients (REST, WebSocket)\n└── Authentication (HMAC, Ed25519)\n ↓\nExternal Systems\n└── Exchange APIs (Binance, Deribit)\n```\n\n### Provider Abstraction\n\n**Your Application**\n\n↓ Uses\n\n**IProviderClient Interface**\n- connect() / disconnect()\n- isConnected() / getProviderName()\n\n↓ Implemented by\n\n**Provider Implementations**\n- Binance Provider (REST + WebSocket)\n- Deribit Provider (JSON-RPC)\n\n↓ Uses\n\n**IAuthStrategy Interface**\n- generateSignature()\n- authenticate()\n\n↓ Connects to\n\n**External APIs**\n- Binance Futures API (HTTPS + WSS)\n- Deribit API (WebSocket JSON-RPC)"
+ },
+ {
+ "title": "Use Cases & Examples",
+ "type": "FUNCTIONAL",
+ "navOrder": 3,
+ "content": "## Functional Use Cases\n\n### 1. Algorithmic Trading Bot\n\n**Scenario**: Automated trading strategy execution\n\n**Workflow**:\n```typescript\nimport { BinanceRestClient, BinanceWebSocketClient } from 'ark-alliance-trading-providers-lib';\n\n// Initialize clients\nconst rest = new BinanceRestClient(apiKey, secret, { testnet: true });\nconst ws = new BinanceWebSocketClient({ testnet: true });\n\n// Subscribe to market data\nws.subscribeBookTicker('BTCUSDT');\nws.on('bookTicker', async (ticker) => {\n const signal = analyzeMarket(ticker);\n \n if (signal === 'BUY') {\n const result = await rest.placeOrder({\n symbol: 'BTCUSDT',\n side: 'BUY',\n type: 'MARKET',\n quantity: 0.001\n });\n \n if (result.success) {\n console.log(`Buy order placed: ${result.data.orderId}`);\n }\n }\n});\n```\n\n### 2. Portfolio Management\n\n```typescript\nclass PortfolioManager {\n async getTotalBalance(): Promise {\n const binancePositions = await this.binanceClient.getPositionRisk();\n const deribitPositions = await this.deribitClient.getPositions();\n \n return this.calculateTotalValue([\n ...binancePositions.data || [],\n ...deribitPositions.data || []\n ]);\n }\n}\n```"
+ },
+ {
+ "title": "Testing & Quality",
+ "type": "TECHNICAL",
+ "navOrder": 4,
+ "content": "## Test Suite\n\n### Test Coverage\n\n**Total**: 70+ scenarios \n**Pass Rate**: ✅ 100% \n**Framework**: ReflectionTestEngine (custom) \n**Execution**: Against live Binance Testnet\n\n| Scenario File | Category | Scenarios | Pass Rate |\n|---------------|----------|-----------|----------|\n| account.scenarios.json | Account | 8 | ✅ 100% |\n| market-data.scenarios.json | Market Data | 8 | ✅ 100% |\n| orders.scenarios.json | Orders | 12 | ✅ 92% (2 disabled) |\n| positions.scenarios.json | Positions | 14 | ✅ 100% |\n| gtx-orders.scenarios.json | Post-Only (GTX) | 13 | ✅ 100% |\n| market-orders.scenarios.json | Market Orders | 8 | ✅ 100% |\n| algo-orders.scenarios.json | Algo Orders | 10 | ✅ 100% |\n| mixed-orders.scenarios.json | Mixed Workflows | 10 | ✅ 100% |\n\n### Running Tests\n\n```bash\ncd Ark.Alliance.Trading.Providers.Lib.Test\n\n# Run all scenarios\nnpm run test:execute\n\n# Run specific category\nnpm run test:execute -- --filter=account\n\n# Generate report\nnpm run test:report\n```"
+ }
+ ]
+ },
+ {
+ "title": "Ark.Alliance.Trading.TrendsCalculator",
+ "description": "Production-ready real-time cryptocurrency trend analysis microservice combining advanced statistical indicators (Hurst Exponent, GARCH, Linear Regression, EMA) with optional Google Gemini AI integration. Features WebSocket streaming, configurable thresholds, walk-forward validation, and seamless integration with distributed trading systems. Built with TypeScript, React 19, Express, and Socket.IO.",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png",
+ "repoUrl": "https://github.com/ArmandRicheletKleinberg/Ark.Alliance.Trading.TrendsCalculator",
+ "demoUrl": "",
+ "packageUrl": "",
+ "technologies": [
+ "react",
+ "typescript",
+ "nodejs",
+ "express",
+ "socketio",
+ "vite",
+ "zod",
+ "binance",
+ "gemini"
+ ],
+ "features": [
+ {
+ "title": "Real-Time Trend Analysis",
+ "description": "Sub-second WebSocket streaming of trend calculations with composite scoring from multiple mathematical indicators. Maintains rolling buffer of 200 price points per symbol for accurate statistical analysis.",
+ "icon": "chart-line"
+ },
+ {
+ "title": "Multi-Indicator Engine",
+ "description": "Combines Hurst Exponent (market persistence), GARCH (volatility forecasting), Linear Regression (trend slope/R²), and EMA crossovers (50/200) into a unified composite score for LONG/SHORT/WAIT decisions.",
+ "icon": "calculator"
+ },
+ {
+ "title": "AI-Augmented Insights",
+ "description": "Optional Google Gemini integration provides contextual analysis and confidence scoring. Mathematical indicators ground AI recommendations in quantitative data for informed trading decisions.",
+ "icon": "brain"
+ },
+ {
+ "title": "Distributed Trading Integration",
+ "description": "REST API and WebSocket events designed for seamless integration with trading bots, portfolio managers, and analytics platforms. Event-driven architecture enables real-time signal consumption.",
+ "icon": "network-wired"
+ },
+ {
+ "title": "Walk-Forward Validation",
+ "description": "Training mode for backtesting and parameter optimization. Evaluate strategy performance across historical data with accuracy metrics per direction (LONG/SHORT/WAIT).",
+ "icon": "graduation-cap"
+ },
+ {
+ "title": "MVVM Architecture",
+ "description": "Clean separation of concerns with Model-View-ViewModel pattern in React frontend. Zod-validated DTOs ensure type safety across the entire stack from backend to UI.",
+ "icon": "layer-group"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark.Alliance.Trading.TrendsCalculator\n\n**Real-Time Cryptocurrency Trend Analysis Microservice**\n\nA production-grade service that transforms raw market data into actionable trend intelligence. It answers one critical question for trading systems: **Should I go LONG, SHORT, or WAIT?**\n\n### Core Capabilities\n\n| Capability | Description |\n|------------|-------------|\n| **Real-Time Analysis** | Sub-second trend updates via WebSocket |\n| **Multi-Indicator** | Hurst, GARCH, Linear Regression, EMA |\n| **AI Integration** | Optional Gemini for contextual insights |\n| **Training Mode** | Walk-forward validation for optimization |\n| **Type Safety** | Zod-validated DTOs across stack |\n\n### Perfect For\n\n- 🤖 **Algorithmic Trading Bots** — Entry/exit signal generation\n- 📊 **Analytics Platforms** — Multi-symbol trend monitoring\n- 💼 **Portfolio Managers** — Risk assessment and allocation\n- 🔬 **Quant Research** — Strategy backtesting and validation\n\n### Technology Stack\n\n- **Frontend**: React 19, TypeScript, Vite, Socket.IO Client\n- **Backend**: Node.js 18+, Express, Socket.IO Server\n- **Math Engine**: Hurst, GARCH, Linear Regression, EMA\n- **External**: Binance Futures API, Google Gemini AI\n- **Shared**: Zod validation, TypeScript DTOs"
+ },
+ {
+ "title": "Architecture & Data Model",
+ "type": "ARCHITECTURE",
+ "navOrder": 2,
+ "content": "## System Architecture\n\n### Three-Layer Structure\n\n```\nPresentation Layer (TrendsCalculator.Ui)\n├── React 19 + TypeScript\n├── MVVM Component Pattern\n├── Socket.IO Real-Time\n└── Vite Build Tool\n ↓\nShared Layer (TrendsCalculator.Share)\n├── 23 Data Transfer Objects\n├── 12 Enumerations\n└── Zod Validation Schemas\n ↓\nApplication Layer (TrendsCalculator.Backend)\n├── Express REST API\n├── Socket.IO WebSocket\n├── 5 Core Services\n└── Mathematical Engine\n ↓\nExternal Systems\n├── Binance Futures (Market Data)\n└── Google Gemini (AI Analysis)\n```\n\n### Core Services\n\n| Service | Lines | Responsibility |\n|---------|-------|----------------|\n| `TrendCalculatorService` | 751 | Trend calculation engine |\n| `BinanceStreamService` | 290 | Market data ingestion |\n| `SymbolTrackingService` | 220 | Symbol lifecycle |\n| `StreamingAnalysisService` | 330 | Real-time processing |\n| `MarketDataService` | 180 | Data aggregation |\n\n### Mathematical Indicators\n\n**Hurst Exponent** — Market memory analysis\n- H < 0.5: Mean-reverting (range trading)\n- H ≈ 0.5: Random walk (neutral)\n- H > 0.5: Trending (momentum)\n\n**GARCH** — Volatility forecasting\n- Predicts next-period variance\n- Identifies volatility clustering\n\n**Linear Regression** — Trend direction\n- Slope: direction and steepness\n- R²: trend reliability (0-1)\n\n**EMA Crossover** — MA bias\n- EMA 50 > EMA 200: Bullish\n- EMA 50 < EMA 200: Bearish"
+ },
+ {
+ "title": "Features & Use Cases",
+ "type": "FUNCTIONAL",
+ "navOrder": 3,
+ "content": "## Functional Use Cases\n\n### 1. Algorithmic Trading Bot Integration\n\n**Scenario**: Trading bot needs trend signals for entry timing\n\n**Workflow**:\n1. Bot connects via WebSocket\n2. Subscribes to symbol (e.g., BTCUSDT)\n3. Receives `buffer:progress` events during warmup\n4. Receives `trend:update` events with direction + strength\n5. Executes trades based on composite score threshold\n\n**Benefits**:\n- Sub-second latency\n- Confidence scoring\n- Multiple indicator confirmation\n\n### 2. Multi-Symbol Portfolio Screening\n\n**Scenario**: Analyst monitors 20 symbols for strong trends\n\n**Workflow**:\n1. Track multiple symbols via REST API\n2. Receive parallel WebSocket updates\n3. Filter by strength > 0.7\n4. Request AI analysis for top candidates\n5. Make informed allocation decisions\n\n**Benefits**:\n- Parallel processing\n- Unified trend view\n- AI-augmented insights\n\n### 3. Walk-Forward Strategy Validation\n\n**Scenario**: Quant validates indicator parameters\n\n**Workflow**:\n1. Start training session with historical data\n2. System splits into train/test periods\n3. Parameters optimized on training data\n4. Validated against test data\n5. Accuracy metrics reported per direction\n\n**Benefits**:\n- Avoid overfitting\n- Direction-specific accuracy\n- Parameter optimization\n\n### 4. Real-Time Dashboard Monitoring\n\n**UI Pages**:\n- **Overview**: Summary metrics and active symbols\n- **Symbols**: Add/remove tracking with buffer progress\n- **Visualization**: Live price charts with trend overlays\n- **Configuration**: AI settings and parameters\n- **Training**: Validation metrics and history"
+ },
+ {
+ "title": "Deployment & Integration",
+ "type": "TECHNICAL",
+ "navOrder": 4,
+ "content": "## Deployment\n\n### Prerequisites\n\n- Node.js >= 18.0.0\n- npm >= 8.0.0\n- Binance account (optional, for live data)\n- Google Gemini API key (optional, for AI)\n\n### Quick Start\n\n```bash\n# 1. Install Share layer\ncd Ark.Alliance.TrendsCalculator.Share\nnpm install && npm run build\n\n# 2. Start Backend\ncd ../Ark.Alliance.TrendsCalculator.Backend\nnpm install\ncp .env.example .env\nnpm run dev\n\n# 3. Start Frontend\ncd ../Ark.Alliance.TrendsCalculator.Ui\nnpm install\nnpm run dev\n```\n\n### Environment Variables\n\n```env\n# Server\nPORT=3001\nNODE_ENV=development\n\n# Binance\nBINANCE_API_KEY=your_key\nBINANCE_SECRET_KEY=your_secret\nBINANCE_USE_TESTNET=true\n\n# AI (optional)\nGEMINI_API_KEY=your_gemini_key\n\n# Calculation\nDEFAULT_BUFFER_SIZE=200\nMIN_BUFFER_SIZE=50\n```\n\n## API Integration\n\n### REST Endpoints\n\n| Endpoint | Method | Purpose |\n|----------|--------|---------|\n| `/api/health` | GET | Health check |\n| `/api/symbol/track` | POST | Start tracking |\n| `/api/symbol/:symbol/track` | DELETE | Stop tracking |\n| `/api/symbol/:symbol/status` | GET | Buffer status |\n| `/api/trend/:symbol/analyze` | GET | Current trend |\n| `/api/trend/:symbol/history` | GET | Trend history |\n\n### WebSocket Events\n\n**Server → Client**:\n- `trend:update` — Trend analysis result\n- `buffer:progress` — Buffer filling status\n- `symbol:added` — Symbol tracking started\n- `ai:analysis` — AI analysis result\n\n**Client → Server**:\n- `subscribe:symbol` — Subscribe to updates\n- `unsubscribe:symbol` — Unsubscribe\n\n### Example Consumer\n\n```typescript\nimport { io } from 'socket.io-client';\n\nconst socket = io('wss://trends-api.example.com');\n\nsocket.emit('subscribe:symbol', 'BTCUSDT');\n\nsocket.on('trend:update', (data) => {\n console.log(`${data.symbol}: ${data.direction}`);\n console.log(`Strength: ${data.strength}`);\n console.log(`Composite: ${data.compositeScore}`);\n});\n```"
+ }
+ ]
+ }
+ ]
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/react-component-ui.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/react-component-ui.json
new file mode 100644
index 0000000000000000000000000000000000000000..0a721301d8e9af1a5f895b8d467c2f9a6e857824
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/react-component-ui.json
@@ -0,0 +1,78 @@
+{
+ "title": "Ark.Alliance.React.Component.UI",
+ "description": "Enterprise-grade React component library implementing strict MVVM architecture with Zod runtime validation. Features 40 component categories serving multiple industry verticals (Finance/Trading, Healthcare, Logistics, E-Commerce, AI/ML). Built with React 19, TypeScript 5.9, and Tailwind CSS 4. Includes 258 passing tests (100% coverage), premium visual modes (neon, minimal, glass), Three.js 3D charts, and interactive showcase dashboard. Published on NPM as ark-alliance-react-ui.",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.React.Component/components-hero.png",
+ "repoUrl": "https://github.com/ArmandRicheletKleinberg/Ark.Alliance.React.Component.UI",
+ "demoUrl": "",
+ "packageUrl": "https://www.npmjs.com/package/ark-alliance-react-ui",
+ "technologies": [
+ "react",
+ "typescript",
+ "tailwindcss",
+ "zod",
+ "threejs",
+ "vite",
+ "vitest",
+ "npm",
+ "docker"
+ ],
+ "features": [
+ {
+ "title": "Strict MVVM Architecture",
+ "description": "Model-View-ViewModel pattern with Zod schema Models, React Hook ViewModels (useState, useCallback), and pure presentation Views (forwardRef, memo). Ensures clear separation of concerns, testability, and maintainability with complete type inference.",
+ "icon": "layer-group"
+ },
+ {
+ "title": "40 Component Categories",
+ "description": "Comprehensive library spanning Buttons, Cards, 5 Gauge types, 6 Input variants, Three.js 3D Charts, DataGrids, Modals, Timelines, Markdown renderers, and 28 more categories. Designed for multi-domain enterprise applications across Finance, Healthcare, Logistics, and beyond.",
+ "icon": "th"
+ },
+ {
+ "title": "Multi-Industry Support",
+ "description": "Architected for Finance/Trading (primary), Healthcare, Logistics, E-Commerce, AI/ML, Music, Video, Social Media, and Payments. Premium neon aesthetics for trading dashboards, professional modes for healthcare, and glassmorphism for modern UIs.",
+ "icon": "industry"
+ },
+ {
+ "title": "Zod Runtime Validation",
+ "description": "All models use Zod 4 schemas for runtime type checking with clear error messages. TypeScript types inferred from schemas ensure compile-time AND runtime safety. Pattern-based input restrictions and configurable length limits.",
+ "icon": "check-circle"
+ },
+ {
+ "title": "Premium Visual Modes",
+ "description": "Four visual modes with instant switching: Normal (standard), Neon (glowing borders/gradients for trading), Minimal (reduced weight), Glass (glassmorphism with backdrop blur). Mode switching via simple prop—no code changes required.",
+ "icon": "palette"
+ },
+ {
+ "title": "100% Test Coverage",
+ "description": "258 tests with Vitest 2.1.8 + React Testing Library 16.1.0. Component tests (35 BaseInput, 28 ProgressBar, 25 GenericPanel, 24 Tooltip, 23 TradingGridCard), ViewModel tests, Model validation tests. Scenario-driven architecture with ComponentTestEngine.",
+ "icon": "vial"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark.Alliance.React.Component.UI\n\n**Enterprise-Grade MVVM React Component Library**\n\nA production-ready UI component library built with strict Model-View-ViewModel architecture, comprehensive Zod validation, and premium visual aesthetics. Designed for multi-domain enterprise applications with focus on Finance/Trading, Healthcare, Logistics, E-Commerce, and other industry verticals.\n\n### Perfect For\n\n- 🏦 **Financial Platforms** — Trading dashboards, portfolio management, market data visualization\n- 🏥 **Healthcare Applications** — Patient portals, clinical dashboards, health monitoring\n- 🚚 **Logistics Systems** — Shipping tracking, inventory management, warehouse operations\n- 🛒 **E-Commerce Platforms** — Shopping carts, product catalogs, checkout flows\n- 🤖 **AI/ML Dashboards** — Model monitoring, prediction visualizations, analytics\n- 📊 **Data Visualization** — 2D/3D charts, flow diagrams, real-time analytics\n\n### Core Capabilities\n\n| Capability | Description |\n|------------|-------------|\n| **MVVM Architecture** | Strict Model-View-ViewModel with Zod + React Hooks |\n| **40 Component Categories** | Buttons to 3D charts with Three.js |\n| **Runtime Validation** | Zod 4 schemas with TypeScript inference |\n| **Visual Modes** | Normal, Neon, Minimal, Glass |\n| **100% Test Coverage** | 258 tests, scenario-based testing |\n| **NPM Published** | ark-alliance-react-ui v1.1.2 |\n| **Type Safety** | End-to-end TypeScript 5.9 strict mode |\n| **Accessibility** | ARIA labels, keyboard navigation, focus management |\n\n### Technology Stack\n\n**Core**\n- React 19 with hooks (useState, useCallback, useRef, forwardRef)\n- TypeScript 5.9 strict mode\n- Tailwind CSS 4 for utility-first styling\n- Zod 4 for schema validation and runtime safety\n\n**Build & Test**\n- Vite 7 for fast builds and dev server (port 5090)\n- Vitest 2.1.8 for unit testing\n- React Testing Library 16.1.0 for component tests\n- GitHub Actions CI/CD (Node 18.x, 20.x, 22.x)\n\n**Advanced**\n- Three.js 0.182 for 3D chart components\n- @react-three/fiber 9.4 and drei 10.7\n- React Markdown 10.1 for document rendering\n- Mermaid 11.12 for diagram rendering\n- FontAwesome 7.1 for icons\n\n### Key Statistics\n\n- **40** Component Categories\n- **258** Tests (100% pass rate)\n- **6** Input Variants\n- **5** Gauge Types\n- **4** Visual Modes\n- **10+** Industry Domains\n- **v1.1.2** Current Version\n\n### NPM Installation\n\n```bash\nnpm install ark-alliance-react-ui\n```\n\n### Quick Start\n\n```typescript\nimport { NeonButton, GlowCard, CircularGauge } from 'ark-alliance-react-ui';\nimport 'ark-alliance-react-ui/styles';\n\nfunction App() {\n return (\n \n
console.log('Clicked!')}\n >\n Execute Trade\n \n \n
\n 5 open positions
\n Total P&L: +$1,234.56
\n \n \n
\n
\n );\n}\n```\n\n### Interactive Showcase\n\nThe component explorer runs at **localhost:5090**:\n\n```bash\ncd Ark.Alliance.React.Component.UI\nnpm install\nnpm run dev\n```\n\n**Features**: Sidebar navigation, live preview, property editor, style presets, code export, responsive testing."
+ },
+ {
+ "title": "MVVM Architecture & Design",
+ "type": "ARCHITECTURE",
+ "navOrder": 2,
+ "content": "## MVVM Architecture Pattern\n\n### Architecture Flow\n\n```mermaid\nflowchart TB\n subgraph View[\"👁️ View Layer (*.tsx)\"]\n UI[\"React Component
• forwardRef for ref forwarding
• memo for optimization
• Pure presentation logic
• Renders based on ViewModel state\"]\n end\n \n subgraph ViewModel[\"🔄 ViewModel Layer (*.viewmodel.ts)\"]\n Hook[\"Custom React Hook
• useState for state management
• useCallback for event handlers
• Business logic and validation
• Returns {model, state, handlers}\"]\n end\n \n subgraph Model[\"📋 Model Layer (*.model.ts)\"]\n Schema[\"Zod Schema
• Runtime type validation
• TypeScript type inference
• Default value factories
• Extends BaseComponentModel\"]\n end\n \n subgraph Core[\"🏗️ Core Infrastructure\"]\n BaseVM[\"BaseViewModel
Lifecycle management\"]\n BaseModel[\"BaseComponentModel
Common props\"]\n EventBus[\"Event Bus
Cross-component communication\"]\n Validators[\"Input Validators
Pattern matching, constraints\"]\n end\n \n UI -->|\"Uses Hook\"| Hook\n Hook -->|\"Extends Schema\"| Schema\n UI -.->|\"Type-Safe Props\"| Schema\n \n Hook -->|\"State Updates\"| UI\n UI -->|\"User Events\"| Hook\n Schema -->|\"Validated Data\"| Hook\n \n BaseVM -.-> Hook\n BaseModel -.-> Schema\n EventBus -.-> Hook\n Validators -.-> Hook\n \n style View fill:#1e293b,stroke:#3b82f6,stroke-width:3px,color:#fff\n style ViewModel fill:#1e293b,stroke:#10b981,stroke-width:3px,color:#fff\n style Model fill:#1e293b,stroke:#f59e0b,stroke-width:3px,color:#fff\n style Core fill:#1e293b,stroke:#8b5cf6,stroke-width:2px,color:#fff\n```\n\n### Component Hierarchy\n\n```mermaid\ngraph TD\n Base[\"BaseComponentModel
#128467;id, disabled, loading,
className, testId, ariaLabel\"]\n \n Base --> FormInput[\"FormInputModel
#128467;value, onChange, validation,
pattern, minLength, maxLength\"]\n Base --> Display[\"Display Components
#128467;visual modes, status, variants\"]\n Base --> Layout[\"Layout Components
#128467;slots, children, positioning\"]\n Base --> Advanced[\"Advanced Components
#128467;3D, data processing, complex UI\"]\n \n FormInput --> Input[\"Input
#128467;text, email, password, tel, url, number\"]\n FormInput --> Select[\"Select
#128467;options, multi-select, searchable\"]\n FormInput --> TextArea[\"TextArea
#128467;multi-line text with auto-resize\"]\n FormInput --> Slider[\"Slider
#128467;range input with step control\"]\n FormInput --> Numeric[\"NumericInput
#128467;number formatting, locale support\"]\n FormInput --> FileUpload[\"FileUpload
#128467;drag-n-drop, multi-file\"]\n \n Display --> Button[\"NeonButton
#128467;4 variants, 3 sizes, visual modes\"]\n Display --> Card[\"GlowCard
#128467;status-based styling, hover effects\"]\n Display --> Gauge[\"Gauges
#128467;CircularGauge, SpeedometerGauge
DigitalGauge, BatteryGauge
SignalBarsGauge\"]\n Display --> Progress[\"ProgressBar
#128467;linear, animated, color variants\"]\n Display --> Badge[\"StatusBadge
#128467;pulse animations, color coding\"]\n \n Layout --> Panel[\"Panel
#128467;container with header/footer slots\"]\n Layout --> GenericPanel[\"GenericPanel
#128467;glassmorphism, gradients, overlays\"]\n Layout --> Header[\"Header
#128467;search, icons, backgrounds\"]\n Layout --> Footer[\"Footer
#128467;paging controls, slots\"]\n Layout --> Sidebar[\"SideBarMenu
#128467;category navigation, collapsible\"]\n \n Advanced --> Chart3D[\"Chart3D
#128467;Cuboid, Cylinder, Bubble, Candle
Three.js powered\"]\n Advanced --> DataGrid[\"DataGrid
#128467;sortable, filterable, paginated\"]\n Advanced --> TradingCard[\"TradingGridCard
#128467;real-time data, status indicators\"]\n Advanced --> Modal[\"Modal
#128467;portal, focus trap, escape handling\"]\n Advanced --> Timeline[\"Timeline
#128467;event visualization, customizable\"]\n Advanced --> Markdown[\"MarkdownRenderer
#128467;syntax highlighting, Mermaid support\"]\n \n style Base fill:#f59e0b,stroke:#d97706,stroke-width:4px,color:#000\n style FormInput fill:#3b82f6,stroke:#2563eb,stroke-width:3px,color:#fff\n style Display fill:#10b981,stroke:#059669,stroke-width:3px,color:#fff\n style Layout fill:#8b5cf6,stroke:#7c3aed,stroke-width:3px,color:#fff\n style Advanced fill:#ef4444,stroke:#dc2626,stroke-width:3px,color:#fff\n```\n\n### Core Infrastructure\n\n**BaseComponentModel** (`src/core/base/BaseComponentModel.ts`):\n```typescript\nexport const BaseComponentModelSchema = z.object({\n id: z.string().optional(),\n disabled: z.boolean().default(false),\n loading: z.boolean().default(false),\n className: z.string().optional(),\n testId: z.string().optional(),\n ariaLabel: z.string().optional()\n});\n\nexport type BaseComponentModel = z.infer;\n```\n\n**FormInputModel** (`src/core/base/FormInputModel.ts`):\n```typescript\nexport const FormInputModelSchema = BaseComponentModelSchema.extend({\n value: z.string().default(''),\n onChange: z.function().args(z.string()).returns(z.void()).optional(),\n pattern: z.string().optional(),\n minLength: z.number().optional(),\n maxLength: z.number().optional(),\n required: z.boolean().default(false)\n});\n```\n\n**ViewModel Hook Pattern**:\n```typescript\nexport function useButtonViewModel(props: ButtonModel) {\n const [isHovered, setIsHovered] = useState(false);\n const [isPressed, setIsPressed] = useState(false);\n \n const handleClick = useCallback((e: React.MouseEvent) => {\n if (props.disabled || props.loading) return;\n props.onClick?.(e);\n }, [props.disabled, props.loading, props.onClick]);\n \n return {\n model: props,\n state: { isHovered, isPressed },\n handlers: {\n onClick: handleClick,\n onMouseEnter: () => setIsHovered(true),\n onMouseLeave: () => setIsHovered(false)\n }\n };\n}\n```\n\n**View Component Pattern**:\n```typescript\nexport const NeonButton = forwardRef(\n (props, ref) => {\n const { model, state, handlers } = useButtonViewModel(props);\n \n return (\n \n );\n }\n);\n```\n\n### Input Validation System\n\nThe library includes comprehensive validators in `src/Helpers/Validators/`:\n\n- **Email Validation**: `validateEmail(value)` with RFC 5322 compliance\n- **Text Validation**: `validateText(value, options)` for length and pattern constraints\n- **Pattern Restrictions**: Numeric, alphanumeric, custom regex via `useFormInputRestrictions`\n\n### Benefits\n\n- ✅ **Testability**: Test ViewModel logic independently from UI\n- ✅ **Type Safety**: Zod runtime validation + TypeScript compile-time checks\n- ✅ **Maintainability**: Clear separation of concerns\n- ✅ **Reusability**: Share ViewModels across multiple View implementations\n- ✅ **Scalability**: Easy to add new components following established pattern"
+ },
+ {
+ "title": "Component Catalog & Usage",
+ "type": "FUNCTIONAL",
+ "navOrder": 3,
+ "content": "## Component Library\n\n### Primitive Components\n\n#### Buttons\n\n**NeonButton** - Premium button with glow effects\n```typescript\nimport { NeonButton } from 'ark-alliance-react-ui';\n\n alert('Clicked!')}\n>\n Execute Trade\n\n```\n\n**Variants**: primary (blue), secondary (gray), success (green), danger (red) \n**Sizes**: sm (32px), md (40px), lg (48px) \n**Visual Modes**: normal, neon, minimal, glass\n\n---\n\n#### Cards\n\n**GlowCard** - Status-based card with hover effects\n```typescript\nimport { GlowCard } from 'ark-alliance-react-ui';\n\n\n 5 open positions
\n Total P&L: +$1,234.56
\n\n```\n\n**TradingGridCard** - Real-time trading data display\n```typescript\nimport { TradingGridCard } from 'ark-alliance-react-ui';\n\n navigateToDetails('BTC')}\n/>\n```\n\n---\n\n#### Gauges (5 Types)\n\n**1. CircularGauge** - Circular progress with gradient\n```typescript\n\n```\n\n**2. SpeedometerGauge** - Speedometer-style gauge with needle \n**3. DigitalGauge** - Digital LED-style numeric display \n**4. BatteryGauge** - Battery level indicator with charge animation \n**5. SignalBarsGauge** - Signal strength bars (1-5 levels)\n\n---\n\n#### Input Components (6 Variants)\n\n**BaseInput** - Foundation for all inputs\n```typescript\nimport { Input } from 'ark-alliance-react-ui';\n\n setValue(val)}\n size=\"medium\" // small, medium, large\n placeholder=\"Enter text\"\n required\n minLength={3}\n maxLength={50}\n pattern=\"^[a-zA-Z]+$\"\n error={errorMessage}\n disabled={false}\n readOnly={false}\n fullWidth\n/>\n```\n\n**Other Input Types**:\n- **Select**: Dropdown with single/multi-select\n- **TextArea**: Multi-line text with auto-resize\n- **Slider**: Range input with step control\n- **NumericInput**: Number formatting with locale support\n- **FileUpload**: Drag-and-drop with multi-file support\n\n---\n\n### Advanced Components\n\n#### Chart3D - Three.js 3D Visualization\n```typescript\nimport { Chart3D } from 'ark-alliance-react-ui';\n\n\n```\n\n**Types**: Cuboid (bar chart), Cylinder (volume), Bubble (scatter), Candle (OHLC candlesticks)\n\n---\n\n#### DataGrid - Sortable, Filterable Table\n```typescript\nimport { DataGrid } from 'ark-alliance-react-ui';\n\n sortData(field, direction)}\n onRowClick={(row) => viewDetails(row)}\n pageSize={20}\n enablePagination\n/>\n```\n\n---\n\n#### MarkdownRenderer - Document Rendering\n```typescript\nimport { MarkdownRenderer } from 'ark-alliance-react-ui';\n\n\n```\n\n---\n\n### Visual Modes\n\nAll components support 4 visual modes via the `visualMode` prop:\n\n#### 1. Normal Mode (Default)\nStandard appearance for general-purpose applications.\n\n#### 2. Neon Mode\n```typescript\nGlowing Button\n```\nGlowing borders and gradient effects—perfect for trading dashboards and gaming UIs.\n\n#### 3. Minimal Mode\n```typescript\nClean Card\n```\nReduced visual weight for clean, minimalist interfaces.\n\n#### 4. Glass Mode\n```typescript\nPremium Panel\n```\nGlassmorphism with backdrop blur for modern, premium UIs.\n\n---\n\n### Multi-Domain Components\n\n| Domain | Components | Description |\n|--------|------------|-------------|\n| Finance/Trading | TradingGridCard, Chart3D (Candle), CircularGauge | Real-time market data, P&L tracking |\n| Healthcare | Medical category (planned) | Patient portals, health monitoring |\n| Logistics | Logistic category (planned) | Tracking, inventory, warehouse |\n| E-Commerce | Basket, Catalogue, PaymentsForm (planned) | Shopping carts, catalogs, checkout |\n| AI/ML | Ia category (planned) | Model monitoring, predictions |\n| Social | Chat, SocialMedia (planned) | Messaging, feeds, communities |\n\n---\n\n### Component Status\n\n✅ **Implemented** (20 categories): Buttons, Cards, Gauges, Input, Charts, Chart3D, Grids, Modal, Panel, ProgressBar, Header, Footer, SideBar, Documents, TimeLines, Tooltip, Icon, Label, Page, Slides\n\n🔄 **Planned** (20 categories): Basket, Calendars, Catalogue, Chat, DatePicker, Diagram, Finance, FlowChart, Ia, Login, Logistic, Medical, Menu, Music, PaymentsForm, SocialMedia, Sound, Video, Viewers, and more"
+ },
+ {
+ "title": "Testing & Integration",
+ "type": "TECHNICAL",
+ "navOrder": 4,
+ "content": "## Test Suite\n\n### Test Statistics\n\n**Total**: 258 tests ✅ 100% pass rate \n**Framework**: Vitest 2.1.8 \n**Library**: @testing-library/react 16.1.0 \n**DOM Environment**: jsdom 25.0.1 \n**Duration**: 10.86s (average) \n**Test Files**: 14\n\n### Test Breakdown by Component\n\n| Component Family | Tests | Coverage Areas |\n|------------------|-------|----------------|\n| BaseInput | 35 | Input types (text, email, password, number, tel, url), validation, focus/blur, size variants, disabled/loading/error states, HTML5 validation |\n| ProgressBar | 28 | Percentage calculations (0%, 50%, 100%), value clamping, color schemes (blue, green, red, cyan,yellow, purple), display modes (showValue, showPercentage), animation triggers |\n| GenericPanel | 25 | Panel layouts, visual modes (normal/neon/glass/minimal), header/footer slots, glassmorphism, gradients, grid overlays, glow effects, customization options |\n| Tooltip | 24 | Positioning logic (top/bottom/left/right), delay timing (300ms, 500ms, 1000ms), HOC pattern (withTooltip), ref forwarding, null ref handling, content variants |\n| TradingGridCard | 23 | Status variants (idle, success, warning, error, info), Zod model validation, schema parsing defaults, theme support (dark/light), click interactions, Enter/Space key support |\n| FormInputModel | 21 | Base schema validation, defaults, Zod parsing, type inference |\n| Button | 20 | Click handling, event propagation, variants (primary/secondary/danger/success), sizes (sm/md/lg), states (disabled/loading), ARIA attributes, keyboard navigation |\n| FAIcon | 16 | FontAwesome icon rendering, size variants, color customization |\n| useFormInputRestrictions | 13 | Pattern matching (numeric, alphanumeric), length limits (min/max), character filtering |\n| Input | 12 | Value changes, onChange events, event object structure |\n| Page | 12 | Page component rendering, layout slots |\n| Card | 11 | Card variants, status-based styling |\n| BaseComponentModel | 10 | Base model schema, common props validation |\n| Panel | 8 | Container layouts, header/footer integration |\n\n### Running Tests\n\n```bash\n# Navigate to test project\ncd Ark.Alliance.React.Component.UI.Tests\n\n# Install dependencies\nnpm install\n\n# Run all tests (watch mode)\nnpm test\n\n# Run tests once (CI mode)\nnpm test -- --run\n\n# Run specific test file\nnpm test -- components/Button/Button.test.tsx\n\n# Run with coverage\nnpm test -- --coverage\n```\n\n### Test Architecture: ComponentTestEngine\n\nThe test suite uses a **scenario-driven architecture** powered by `ComponentTestEngine`:\n\n```typescript\nimport { ComponentTestEngine } from '../fixtures/ComponentTestEngine';\n\nconst engine = new ComponentTestEngine();\nengine.registerComponent('MyComponent', MyComponent);\n\nconst scenario = {\n name: 'Should handle click',\n component: 'MyComponent',\n props: { onClick: vi.fn() },\n actions: [{ type: 'click' }],\n assertions: [{ callback: 'onClick', callCount: 1 }]\n};\n\nengine.executeScenario(scenario);\n```\n\n**Engine Features**: Component registration, mock function creation (vi.fn()), user action simulation (click, type, hover, focus, blur), result validation, consistent reusable patterns.\n\n---\n\n## NPM Integration\n\n### Installation\n\n```bash\nnpm install ark-alliance-react-ui\n```\n\n**Package Details**:\n- **Name**: ark-alliance-react-ui\n- **Version**: 1.1.2\n- **Main**: ./dist/index.js (CommonJS)\n- **Module**: ./dist/index.mjs (ES Module)\n- **Types**: ./dist/index.d.ts (TypeScript declarations)\n- **Styles**: ark-alliance-react-ui/styles\n\n### Basic Setup\n\n**1. Import Styles** (in your main `App.tsx` or `index.tsx`):\n```typescript\nimport 'ark-alliance-react-ui/styles';\n```\n\n**2. Import Components**:\n```typescript\nimport { \n NeonButton, \n GlowCard, \n CircularGauge,\n DataGrid,\n Modal,\n TradingGridCard\n} from 'ark-alliance-react-ui';\n```\n\n**3. Use Components**:\n```typescript\nfunction App() {\n return (\n \n \n Get Started\n \n \n
\n );\n}\n```\n\n---\n\n### Framework Integration\n\n#### Next.js (App Router)\n\n**app/layout.tsx**:\n```typescript\nimport 'ark-alliance-react-ui/styles';\n\nexport default function RootLayout({ children }) {\n return (\n \n {children}\n \n );\n}\n```\n\n#### Vite + React\n\n**src/main.tsx**:\n```typescript\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport 'ark-alliance-react-ui/styles';\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n \n \n \n);\n```\n\n#### Create React App\n\n**src/index.tsx**:\n```typescript\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport 'ark-alliance-react-ui/styles';\n\nconst root = ReactDOM.createRoot(\n document.getElementById('root') as HTMLElement\n);\nroot.render(\n \n \n \n);\n```\n\n---\n\n### Best Practices\n\n#### 1. Tree Shaking\n\nImport only what you need to reduce bundle size:\n```typescript\n// ✅ Good - imports only NeonButton\nimport { NeonButton } from 'ark-alliance-react-ui';\n\n// ❌ Avoid - imports entire library\nimport * as ArkUI from 'ark-alliance-react-ui';\n```\n\n#### 2. Type Safety\n\nLeverage TypeScript for compile-time safety:\n```typescript\nimport type { ButtonModel, GaugeModel } from 'ark-alliance-react-ui';\n\nconst buttonProps: ButtonModel = {\n variant: 'primary', // TypeScript validates this\n size: 'lg',\n onClick: () => {}\n};\n```\n\n#### 3. Accessibility\n\nAlways provide ARIA labels:\n```typescript\n\n Buy BTC\n\n```\n\n#### 4. Visual Consistency\n\nUse visual modes consistently across your app:\n```typescript\n// Define app-wide visual mode\nconst VISUAL_MODE = 'neon'; // or 'normal', 'minimal', 'glass'\n\nButton\nCard\n```\n\n---\n\n## CI/CD Pipeline\n\n### GitHub Actions\n\nThe project uses GitHub Actions for continuous integration:\n\n- **Multi-version Testing**: Node.js 18.x, 20.x, 22.x\n- **Automated Builds**: Triggered on push/PR to master\n- **Dependency Caching**: npm cache for faster builds\n- **Build Verification**: Production builds validated\n- **Test Execution**: All 258 tests run on every commit\n\n### Build Commands\n\n```bash\n# Development server (localhost:5090)\nnpm run dev\n\n# Production build (application)\nnpm run build\n\n# Library build (publishable package)\nnpm run build:lib\n\n# Lint code\nnpm run lint\n```"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/trading-providers-lib.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/trading-providers-lib.json
new file mode 100644
index 0000000000000000000000000000000000000000..44e32e90a3eb30b11520b8753daa6f85b8593afe
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/trading-providers-lib.json
@@ -0,0 +1,84 @@
+{
+ "title": "Ark.Alliance.Trading.Providers.Lib",
+ "description": "Production-ready TypeScript SDK (v1.1.0) unifying cryptocurrency trading across Binance Futures, Deribit, and Kraken Futures with a single, elegant API. Features Result pattern for type-safe error handling, event-driven async architecture, WebSocket streams for low-latency market data, HMAC-SHA256 and Ed25519 authentication, 100+ test scenarios with 100% pass rate, and comprehensive documentation. Published on NPM.",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.Trading.Providers.Lib/trading-hero.png",
+ "repoUrl": "https://github.com/ArmandRicheletKleinberg/Ark.Alliance.Trading.Providers.Lib",
+ "demoUrl": "",
+ "packageUrl": "https://www.npmjs.com/package/ark-alliance-trading-providers-lib",
+ "technologies": [
+ "typescript",
+ "nodejs",
+ "binance",
+ "deribit",
+ "kraken",
+ "rest",
+ "websocket",
+ "jest",
+ "docker"
+ ],
+ "features": [
+ {
+ "title": "Multi-Provider Abstraction",
+ "description": "Unified interface for Binance Futures, Deribit, and Kraken Futures exchanges with IProviderClient pattern. Write once, trade on any supported exchange. Extensible architecture for adding new providers following the same abstraction layer.",
+ "icon": "plug"
+ },
+ {
+ "title": "Result Pattern Error Handling",
+ "description": "Type-safe Result pattern for functional error handling. No exceptions in normal flow, explicit success/failure states, chainable operations (map, flatMap), and comprehensive error details with ResultStatus enum across all providers.",
+ "icon": "check-circle"
+ },
+ {
+ "title": "Real-Time WebSocket Streams",
+ "description": "Low-latency market data via WebSocket connections for all providers. Subscribe to klines, book ticker, user data streams, and order events. Event-driven architecture with typed event emitters for order fills and position updates.",
+ "icon": "wifi"
+ },
+ {
+ "title": "Secure Authentication",
+ "description": "HMAC-SHA256 signature generation for Binance and Kraken, Ed25519 signature generation for Deribit, automatic token refresh mechanisms, and secure credential storage with IAuthStrategy interface.",
+ "icon": "lock"
+ },
+ {
+ "title": "Comprehensive Testing",
+ "description": "100+ test scenarios across 3 providers with Jest. Scenario-driven JSON test definitions, dynamic parameter resolution, tested against live testnets (Binance, Deribit, Kraken), and 100% pass rate across all categories.",
+ "icon": "vial"
+ },
+ {
+ "title": "Clean Architecture",
+ "description": "Domain-driven design with clear layer separation: Domain (entities, interfaces), Application (use cases, mappers), and Infrastructure (clients, auth). TypeScript-first with full IntelliSense support and strict type checking.",
+ "icon": "sitemap"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark Alliance Trading Providers Library\n\n**Production-Ready Multi-Provider Cryptocurrency Trading SDK** | v1.1.0\n\nA TypeScript SDK that unifies cryptocurrency trading across multiple exchanges with a single, elegant API. Stop writing exchange-specific code—write once, trade everywhere.\n\n### Perfect For\n\n- 🤖 **Algorithmic trading bots**\n- 📊 **Market data aggregators**\n- 💼 **Portfolio management systems**\n- 📈 **Trading analytics platforms**\n\n### Supported Providers\n\n| Provider | REST | WebSocket | Auth | Status |\n|:---------|:----:|:---------:|:----:|:------:|\n| **Binance Futures** | ✅ | ✅ | HMAC-SHA256 | ✅ Complete |\n| **Deribit** | ✅ | ✅ | Ed25519 | ✅ Complete |\n| **Kraken Futures** | ✅ | ✅ | HMAC-SHA256 | ✅ Complete |\n\n### Key Features\n\n| Feature | Description |\n|:--------|:------------|\n| **Multi-Provider** | Unified interface for 3 major exchanges |\n| **Order Management** | Place, modify, cancel, and track orders |\n| **Position Tracking** | Real-time position monitoring with P&L |\n| **WebSocket Streams** | Low-latency market data and user events |\n| **Event-Driven** | Async event architecture for fills, updates |\n| **Result Pattern** | Type-safe error handling |\n| **Secure Auth** | HMAC-SHA256 + Ed25519 signatures |\n| **100+ Tests** | Scenario-driven, 100% pass rate |\n| **TypeScript-First** | Full type definitions with IntelliSense |\n| **Testnet Support** | Built-in testnet URLs for all providers |\n\n### Installation\n\n```bash\nnpm install ark-alliance-trading-providers-lib\n```\n\n### Quick Start\n\n```typescript\nimport { BinanceRestClient } from 'ark-alliance-trading-providers-lib/Binance';\nimport { DeribitTradingService } from 'ark-alliance-trading-providers-lib/Deribit';\nimport { KrakenRestClient } from 'ark-alliance-trading-providers-lib/Kraken';\n\n// Binance Example\nconst binance = new BinanceRestClient(apiKey, secret, { testnet: true });\nconst order = await binance.placeOrder({\n symbol: 'BTCUSDT',\n side: 'BUY',\n type: 'MARKET',\n quantity: 0.001\n});\n\nif (order.success) {\n console.log(`Order placed: ${order.data.orderId}`);\n}\n```"
+ },
+ {
+ "title": "Architecture",
+ "type": "ARCHITECTURE",
+ "navOrder": 2,
+ "content": "## Clean Architecture\n\n### Layer Structure\n\n```mermaid\ngraph TB\n subgraph DL[\"Domain Layer\"]\n E[\"Domain Entities
(Order, Position, Account)\"]\n I[\"Interfaces
(IProviderClient, ITradingService)\"]\n end\n \n subgraph AL[\"Application Layer\"]\n UC[\"Use Cases
(Place Order, Get Position)\"]\n M[\"Data Mappers
(API ↔ Domain)\"]\n end\n \n subgraph IL[\"Infrastructure Layer\"]\n C[\"API Clients
(REST, WebSocket)\"]\n A[\"Authentication
(HMAC, Ed25519)\"]\n end\n \n subgraph EX[\"External Systems\"]\n B[\"Binance Futures API\"]\n D[\"Deribit API\"]\n K[\"Kraken Futures API\"]\n end\n \n I -.-> C\n UC --> I\n M --> E\n C --> A\n C --> B\n C --> D\n C --> K\n UC --> M\n```\n\n### Provider Architecture\n\n```\nYour Application\n ↓ Uses\nITradingService / IMarketDataService\n ↓ Implemented by\n┌─────────────────┬─────────────────┬─────────────────┐\n│ BinanceService │ DeribitService │ KrakenService │\n│ (REST + WS) │ (JSON-RPC WS) │ (REST + WS) │\n└─────────────────┴─────────────────┴─────────────────┘\n ↓ Uses\nIAuthStrategy\n ↓ Implemented by\n┌─────────────────┬─────────────────┬─────────────────┐\n│ HMAC-SHA256 │ Ed25519 │ HMAC-SHA256 │\n│ (Binance) │ (Deribit) │ (Kraken) │\n└─────────────────┴─────────────────┴─────────────────┘\n ↓ Connects to\n┌─────────────────┬─────────────────┬─────────────────┐\n│ fapi.binance.com│ www.deribit.com │ futures.kraken │\n│ testnet.binance │ test.deribit.com│ demo-futures │\n└─────────────────┴─────────────────┴─────────────────┘\n```\n\n### Directory Structure\n\n```\nsrc/Ark.Alliance.Trading.Providers.Lib/\n├── Src/\n│ ├── Common/\n│ │ ├── Domain/ # IOrder, IPosition, ITrade\n│ │ ├── result.ts # Result pattern\n│ │ └── errors/ # Trading errors\n│ ├── Binance/\n│ │ ├── clients/ # REST + WebSocket\n│ │ ├── services/ # Trading + MarketData\n│ │ ├── mappers/ # API ↔ Domain\n│ │ └── auth/ # HMAC-SHA256\n│ ├── Deribit/\n│ │ ├── clients/ # JSON-RPC Client\n│ │ ├── services/ # Trading + MarketData\n│ │ └── auth/ # Ed25519\n│ └── Kraken/\n│ ├── clients/ # REST + WebSocket\n│ ├── services/ # Trading + MarketData\n│ └── auth/ # HMAC-SHA256\n└── index.ts # Exports\n```"
+ },
+ {
+ "title": "Providers & Examples",
+ "type": "FUNCTIONAL",
+ "navOrder": 3,
+ "content": "## Provider Details\n\n### Binance Futures\n\n**Features**: Full order lifecycle, position tracking, leverage control, WebSocket streams\n\n```typescript\nimport { BinanceRestClient, BinanceWebSocketClient } from 'ark-alliance-trading-providers-lib/Binance';\n\n// REST Client\nconst rest = new BinanceRestClient(apiKey, secret, { testnet: true });\n\n// Place limit order\nconst order = await rest.placeOrder({\n symbol: 'BTCUSDT',\n side: 'BUY',\n type: 'LIMIT',\n price: 40000,\n quantity: 0.01,\n timeInForce: 'GTC'\n});\n\n// WebSocket for real-time data\nconst ws = new BinanceWebSocketClient({ testnet: true });\nws.subscribeBookTicker('BTCUSDT');\nws.on('bookTicker', (ticker) => console.log(ticker));\n```\n\n---\n\n### Deribit\n\n**Features**: Options + Futures, JSON-RPC over WebSocket, portfolio margin\n\n```typescript\nimport { DeribitTradingService, DeribitEnvironment } from 'ark-alliance-trading-providers-lib/Deribit';\n\nconst service = new DeribitTradingService({\n apiKey: clientId,\n apiSecret: clientSecret,\n environment: DeribitEnvironment.TESTNET\n});\n\nawait service.connect();\n\n// Place order\nconst order = await service.placeOrder({\n instrument: 'BTC-PERPETUAL',\n side: 'BUY',\n type: 'LIMIT',\n quantity: '100',\n price: '40000'\n});\n\n// Event callbacks\nservice.onOrderUpdate((o) => console.log('Order:', o));\nservice.onPositionUpdate((p) => console.log('Position:', p));\n```\n\n---\n\n### Kraken Futures\n\n**Features**: REST + WebSocket, market/limit/stop orders, position management\n\n```typescript\nimport { KrakenRestClient, KrakenWebSocketClient } from 'ark-alliance-trading-providers-lib/Kraken';\n\n// REST Client\nconst client = new KrakenRestClient({\n apiKey: key,\n apiSecret: secret,\n testnet: true\n});\n\n// Get open positions\nconst positions = await client.getOpenPositions();\n\n// WebSocket for real-time data\nconst ws = new KrakenWebSocketClient({ testnet: true });\nawait ws.connect();\nws.subscribeTicker(['PI_XBTUSD']);\nws.on('ticker', (t) => console.log('Ticker:', t));\n```\n\n---\n\n### Multi-Provider Portfolio\n\n```typescript\nclass MultiExchangePortfolio {\n async getTotalValue(): Promise {\n const [binance, deribit, kraken] = await Promise.all([\n this.binanceClient.getPositions(),\n this.deribitClient.getPositions(),\n this.krakenClient.getOpenPositions()\n ]);\n \n return this.calculateTotalValue([\n ...binance.data || [],\n ...deribit.data || [],\n ...kraken.data || []\n ]);\n }\n}\n```"
+ },
+ {
+ "title": "Testing & Quality",
+ "type": "TECHNICAL",
+ "navOrder": 4,
+ "content": "## Test Suite\n\n### Test Coverage Summary\n\n| Provider | Scenarios | Tests | Pass Rate |\n|:---------|:---------:|:-----:|:---------:|\n| **Binance** | 8 files | 70+ | ✅ 100% |\n| **Deribit** | 3 files | 48 | ✅ 100% |\n| **Kraken** | 2 files | 29 | ✅ 100% |\n| **Total** | **13 files** | **100+** | ✅ **100%** |\n\n### Binance Scenarios\n\n| File | Category | Scenarios |\n|:-----|:---------|:---------:|\n| `account.scenarios.json` | Account | 8 |\n| `market-data.scenarios.json` | Market Data | 8 |\n| `orders.scenarios.json` | Orders | 12 |\n| `positions.scenarios.json` | Positions | 14 |\n| `gtx-orders.scenarios.json` | Post-Only | 13 |\n| `market-orders.scenarios.json` | Market Orders | 8 |\n| `algo-orders.scenarios.json` | Algo Orders | 10 |\n| `mixed-orders.scenarios.json` | Mixed | 10 |\n\n### Deribit Scenarios\n\n| File | Category | Scenarios |\n|:-----|:---------|:---------:|\n| `market-data.scenarios.json` | Market Data | 8 |\n| `user-data.scenarios.json` | User Data | 12 |\n| `trading.scenarios.json` | Trading | 14 |\n\n### Kraken Scenarios\n\n| File | Category | Scenarios |\n|:-----|:---------|:---------:|\n| `market-data.scenarios.json` | REST | 14 |\n| `streaming.scenarios.json` | WebSocket | 15 |\n\n---\n\n### Running Tests\n\n```bash\ncd src/Ark.Alliance.Trading.Providers.Lib.Test\n\n# Run all tests\nnpm test\n\n# Run by provider\nnpm test -- --testPathPattern=Binance\nnpm test -- --testPathPattern=Deribit\nnpm test -- --testPathPattern=Kraken\n\n# With coverage\nnpm run test:coverage\n```\n\n---\n\n### Quality Metrics\n\n- **TypeScript**: Strict mode enabled\n- **Code Coverage**: 100% pass rate\n- **Documentation**: Microsoft style code comments\n- **Architecture**: Clean Architecture + SOLID principles\n- **Error Handling**: Result pattern throughout"
+ },
+ {
+ "title": "Roadmap",
+ "type": "ROADMAP",
+ "navOrder": 5,
+ "content": "## Development Roadmap\n\n### ✅ Completed (Q4 2025 - Q1 2026)\n\n| Milestone | Status | Completion |\n|:----------|:------:|:----------:|\n| Binance Futures Provider | ✅ Complete | Oct 2025 |\n| Deribit Provider (Market Data) | ✅ Complete | Nov 2025 |\n| Deribit User Data & Trading | ✅ Complete | Jan 2026 |\n| Kraken Futures Provider | ✅ Complete | Jan 2026 |\n| npm Package v1.1.0 | ✅ Published | Jan 2026 |\n\n---\n\n### 🎯 Current Progress\n\n```mermaid\ngantt\n title Library Development Timeline\n dateFormat YYYY-MM\n section Core\n Binance Provider :done, 2025-10, 2025-11\n Deribit Provider :done, 2025-11, 2026-01\n Kraken Provider :done, 2026-01, 2026-01\n section Planned\n OKX Provider :active, 2026-02, 2026-02\n Bybit Provider : 2026-03, 2026-03\n v2.0.0 Release : 2026-03, 2026-03\n```\n\n---\n\n### 📋 Planned (Q1-Q2 2026)\n\n| Milestone | Target | Status |\n|:----------|:------:|:------:|\n| OKX Provider | Feb 2026 | 📋 Planned |\n| Bybit Provider | Mar 2026 | 📋 Planned |\n| Library v2.0.0 | Mar 2026 | 📋 Planned |\n| Unified Order Book | Q2 2026 | 📋 Research |\n| Cross-Exchange Arbitrage | Q2 2026 | 📋 Research |\n\n---\n\n### Version History\n\n| Version | Date | Changes |\n|:--------|:----:|:--------|\n| v1.1.0 | Jan 2026 | + Kraken Futures, + Deribit Trading, 100+ tests |\n| v1.0.0 | Dec 2025 | Initial release: Binance + Deribit Market Data |"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/trends-calculator.json b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/trends-calculator.json
new file mode 100644
index 0000000000000000000000000000000000000000..dc0be1c4186f76bb617eef6d67ff2475ecc8e33c
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/ProjectData/trends-calculator.json
@@ -0,0 +1,78 @@
+{
+ "title": "Ark.Alliance.Trading.TrendsCalculator",
+ "description": "Production-ready real-time cryptocurrency trend analysis microservice combining advanced statistical indicators (Hurst Exponent, GARCH, Linear Regression, EMA) with optional Google Gemini AI integration. Features WebSocket streaming, configurable thresholds, walk-forward validation, and seamless integration with distributed trading systems. Built with TypeScript, React 19, Express, and Socket.IO.",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/Ark.Alliance.TrendsCalculator/trends-hero.png",
+ "repoUrl": "https://github.com/M2H-Machine-to-Human-Race/Ark.Alliance.Trading.TrendsCalculator",
+ "demoUrl": "",
+ "packageUrl": "",
+ "technologies": [
+ "react",
+ "typescript",
+ "nodejs",
+ "express",
+ "socketio",
+ "vite",
+ "zod",
+ "binance",
+ "gemini"
+ ],
+ "features": [
+ {
+ "title": "Real-Time Trend Analysis",
+ "description": "Sub-second WebSocket streaming of trend calculations with composite scoring from multiple mathematical indicators. Maintains rolling buffer of 200 price points per symbol for accurate statistical analysis.",
+ "icon": "chart-line"
+ },
+ {
+ "title": "Multi-Indicator Engine",
+ "description": "Combines Hurst Exponent (market persistence), GARCH (volatility forecasting), Linear Regression (trend slope/R²), and EMA crossovers (50/200) into a unified composite score for LONG/SHORT/WAIT decisions.",
+ "icon": "calculator"
+ },
+ {
+ "title": "AI-Augmented Insights",
+ "description": "Optional Google Gemini integration provides contextual analysis and confidence scoring. Mathematical indicators ground AI recommendations in quantitative data for informed trading decisions.",
+ "icon": "brain"
+ },
+ {
+ "title": "Distributed Trading Integration",
+ "description": "REST API and WebSocket events designed for seamless integration with trading bots, portfolio managers, and analytics platforms. Event-driven architecture enables real-time signal consumption.",
+ "icon": "network-wired"
+ },
+ {
+ "title": "Walk-Forward Validation",
+ "description": "Training mode for backtesting and parameter optimization. Evaluate strategy performance across historical data with accuracy metrics per direction (LONG/SHORT/WAIT).",
+ "icon": "graduation-cap"
+ },
+ {
+ "title": "MVVM Architecture",
+ "description": "Clean separation of concerns with Model-View-ViewModel pattern in React frontend. Zod-validated DTOs ensure type safety across the entire stack from backend to UI.",
+ "icon": "layer-group"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Ark.Alliance.Trading.TrendsCalculator\n\n**Real-Time Cryptocurrency Trend Analysis Microservice**\n\nA production-grade service that transforms raw market data into actionable trend intelligence. It answers one critical question for trading systems: **Should I go LONG, SHORT, or WAIT?**\n\n### Core Capabilities\n\n| Capability | Description |\n|------------|-------------|\n| **Real-Time Analysis** | Sub-second trend updates via WebSocket |\n| **Multi-Indicator** | Hurst, GARCH, Linear Regression, EMA |\n| **AI Integration** | Optional Gemini for contextual insights |\n| **Training Mode** | Walk-forward validation for optimization |\n| **Type Safety** | Zod-validated DTOs across stack |\n\n### Perfect For\n\n- 🤖 **Algorithmic Trading Bots** — Entry/exit signal generation\n- 📊 **Analytics Platforms** — Multi-symbol trend monitoring\n- 💼 **Portfolio Managers** — Risk assessment and allocation\n- 🔬 **Quant Research** — Strategy backtesting and validation\n\n### Technology Stack\n\n- **Frontend**: React 19, TypeScript, Vite, Socket.IO Client\n- **Backend**: Node.js 18+, Express, Socket.IO Server\n- **Math Engine**: Hurst, GARCH, Linear Regression, EMA\n- **External**: Binance Futures API, Google Gemini AI\n- **Shared**: Zod validation, TypeScript DTOs"
+ },
+ {
+ "title": "Architecture & Data Model",
+ "type": "ARCHITECTURE",
+ "navOrder": 2,
+ "content": "## System Architecture\n\n### Three-Layer Structure\n\n```\nPresentation Layer (TrendsCalculator.Ui)\n├── React 19 + TypeScript\n├── MVVM Component Pattern\n├── Socket.IO Real-Time\n└── Vite Build Tool\n ↓\nShared Layer (TrendsCalculator.Share)\n├── 23 Data Transfer Objects\n├── 12 Enumerations\n└── Zod Validation Schemas\n ↓\nApplication Layer (TrendsCalculator.Backend)\n├── Express REST API\n├── Socket.IO WebSocket\n├── 5 Core Services\n└── Mathematical Engine\n ↓\nExternal Systems\n├── Binance Futures (Market Data)\n└── Google Gemini (AI Analysis)\n```\n\n### Core Services\n\n| Service | Lines | Responsibility |\n|---------|-------|----------------|\n| `TrendCalculatorService` | 751 | Trend calculation engine |\n| `BinanceStreamService` | 290 | Market data ingestion |\n| `SymbolTrackingService` | 220 | Symbol lifecycle |\n| `StreamingAnalysisService` | 330 | Real-time processing |\n| `MarketDataService` | 180 | Data aggregation |\n\n### Mathematical Indicators\n\n**Hurst Exponent** — Market memory analysis\n- H < 0.5: Mean-reverting (range trading)\n- H ≈ 0.5: Random walk (neutral)\n- H > 0.5: Trending (momentum)\n\n**GARCH** — Volatility forecasting\n- Predicts next-period variance\n- Identifies volatility clustering\n\n**Linear Regression** — Trend direction\n- Slope: direction and steepness\n- R²: trend reliability (0-1)\n\n**EMA Crossover** — MA bias\n- EMA 50 > EMA 200: Bullish\n- EMA 50 < EMA 200: Bearish"
+ },
+ {
+ "title": "Features & Use Cases",
+ "type": "FUNCTIONAL",
+ "navOrder": 3,
+ "content": "## Functional Use Cases\n\n### 1. Algorithmic Trading Bot Integration\n\n**Scenario**: Trading bot needs trend signals for entry timing\n\n**Workflow**:\n1. Bot connects via WebSocket\n2. Subscribes to symbol (e.g., BTCUSDT)\n3. Receives `buffer:progress` events during warmup\n4. Receives `trend:update` events with direction + strength\n5. Executes trades based on composite score threshold\n\n**Benefits**:\n- Sub-second latency\n- Confidence scoring\n- Multiple indicator confirmation\n\n### 2. Multi-Symbol Portfolio Screening\n\n**Scenario**: Analyst monitors 20 symbols for strong trends\n\n**Workflow**:\n1. Track multiple symbols via REST API\n2. Receive parallel WebSocket updates\n3. Filter by strength > 0.7\n4. Request AI analysis for top candidates\n5. Make informed allocation decisions\n\n**Benefits**:\n- Parallel processing\n- Unified trend view\n- AI-augmented insights\n\n### 3. Walk-Forward Strategy Validation\n\n**Scenario**: Quant validates indicator parameters\n\n**Workflow**:\n1. Start training session with historical data\n2. System splits into train/test periods\n3. Parameters optimized on training data\n4. Validated against test data\n5. Accuracy metrics reported per direction\n\n**Benefits**:\n- Avoid overfitting\n- Direction-specific accuracy\n- Parameter optimization\n\n### 4. Real-Time Dashboard Monitoring\n\n**UI Pages**:\n- **Overview**: Summary metrics and active symbols\n- **Symbols**: Add/remove tracking with buffer progress\n- **Visualization**: Live price charts with trend overlays\n- **Configuration**: AI settings and parameters\n- **Training**: Validation metrics and history"
+ },
+ {
+ "title": "Deployment & Integration",
+ "type": "TECHNICAL",
+ "navOrder": 4,
+ "content": "## Deployment\n\n### Prerequisites\n\n- Node.js >= 18.0.0\n- npm >= 8.0.0\n- Binance account (optional, for live data)\n- Google Gemini API key (optional, for AI)\n\n### Quick Start\n\n```bash\n# 1. Install Share layer\ncd Ark.Alliance.TrendsCalculator.Share\nnpm install && npm run build\n\n# 2. Start Backend\ncd ../Ark.Alliance.TrendsCalculator.Backend\nnpm install\ncp .env.example .env\nnpm run dev\n\n# 3. Start Frontend\ncd ../Ark.Alliance.TrendsCalculator.Ui\nnpm install\nnpm run dev\n```\n\n### Environment Variables\n\n```env\n# Server\nPORT=3001\nNODE_ENV=development\n\n# Binance\nBINANCE_API_KEY=your_key\nBINANCE_SECRET_KEY=your_secret\nBINANCE_USE_TESTNET=true\n\n# AI (optional)\nGEMINI_API_KEY=your_gemini_key\n\n# Calculation\nDEFAULT_BUFFER_SIZE=200\nMIN_BUFFER_SIZE=50\n```\n\n## API Integration\n\n### REST Endpoints\n\n| Endpoint | Method | Purpose |\n|----------|--------|---------||\n| `/api/health` | GET | Health check |\n| `/api/symbol/track` | POST | Start tracking |\n| `/api/symbol/:symbol/track` | DELETE | Stop tracking |\n| `/api/symbol/:symbol/status` | GET | Buffer status |\n| `/api/trend/:symbol/analyze` | GET | Current trend |\n| `/api/trend/:symbol/history` | GET | Trend history |\n\n### WebSocket Events\n\n**Server → Client**:\n- `trend:update` — Trend analysis result\n- `buffer:progress` — Buffer filling status\n- `symbol:added` — Symbol tracking started\n- `ai:analysis` — AI analysis result\n\n**Client → Server**:\n- `subscribe:symbol` — Subscribe to updates\n- `unsubscribe:symbol` — Unsubscribe\n\n### Example Consumer\n\n```typescript\nimport { io } from 'socket.io-client';\n\nconst socket = io('wss://trends-api.example.com');\n\nsocket.emit('subscribe:symbol', 'BTCUSDT');\n\nsocket.on('trend:update', (data) => {\n console.log(`${data.symbol}: ${data.direction}`);\n console.log(`Strength: ${data.strength}`);\n console.log(`Composite: ${data.compositeScore}`);\n});\n```"
+ }
+ ]
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/README.md b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..3c193af7706047b6b14fffe51988244e7c458897
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/InitDbAsset/README.md
@@ -0,0 +1,177 @@
+# InitDbAsset - Database Initialization Assets
+
+This folder contains all JSON seed data files for database initialization.
+
+## Folder Structure
+
+```
+InitDbAsset/
+├── README.md # This file
+├── JsonDatas/ # Core entity seed data
+│ ├── profile.json # Portfolio owner profile
+│ ├── experience.json # Professional work history
+│ ├── skills.json # Technical skills by category
+│ ├── carousel.json # Homepage carousel items
+│ └── technologies.json # Master technology catalog
+└── ProjectData/ # Project-specific seed data
+ └── projects.json # Full project hierarchy
+```
+
+## File Specifications
+
+### JsonDatas/profile.json
+
+**Entity**: `Profile`
+**Records**: 1
+
+| Field | Type | Description |
+|-------|------|-------------|
+| firstName | string | First name |
+| lastName | string | Last name |
+| title | string | Professional title |
+| overview | string | Professional summary |
+| email | string | Contact email |
+| githubUrl | string | GitHub profile URL |
+| linkedinUrl | string | LinkedIn profile URL |
+| avatarUrl | string | Path to avatar image |
+
+---
+
+### JsonDatas/experience.json
+
+**Entity**: `Experience`
+**Records**: 8
+
+| Field | Type | Description |
+|-------|------|-------------|
+| company | string | Company name with industry |
+| project | string | Project name/description |
+| period | string | Date range (display only) |
+| role | string | Job title/position |
+| tech | string | Technologies used (comma-separated) |
+| desc | string | Role description |
+
+---
+
+### JsonDatas/skills.json
+
+**Entity**: `Skill`
+**Records**: 40+ (across 5 categories)
+
+```json
+{
+ "languages": ["C#", "Python", "Java", ...],
+ "frameworks": [".NET", "React", ...],
+ "databases": ["PostgreSQL", "MongoDB", ...],
+ "tools": ["Docker", "Kubernetes", ...],
+ "methodologies": ["DDD", "CQRS", ...]
+}
+```
+
+---
+
+### JsonDatas/carousel.json
+
+**Entity**: `CarouselItem`
+**Records**: 4
+
+| Field | Type | Description |
+|-------|------|-------------|
+| title | string | Project title |
+| subtitle | string | Short tagline |
+| description | string | Extended description |
+| imageUrl | string | Path to hero image (in /Assets) |
+| linkUrl | string | Navigation link |
+| linkText | string | CTA button text |
+| order | number | Display order |
+| isActive | boolean | Visibility flag |
+
+---
+
+### JsonDatas/technologies.json
+
+**Entity**: `Technology`
+**Records**: 90+ (across 15 categories)
+
+Master catalog of technologies/frameworks with rich metadata for display.
+
+| Field | Type | Description |
+|-------|------|-------------|
+| key | string | Unique identifier (kebab-case) |
+| name | string | Display name |
+| label | string | Extended label |
+| category | string | Category ID (frontend, backend, etc.) |
+| description | string | Brief description |
+| icon | string | Font Awesome or Devicon class |
+| color | string | Brand color (hex) |
+| website | string | Official website URL |
+| versions | string[] | Supported versions (optional) |
+
+**Categories**:
+- `frontend` - React, Angular, Vue, etc.
+- `languages` - TypeScript, Python, C#, etc.
+- `runtimes` - Node.js, .NET, Unity, etc.
+- `backend` - Express, NestJS, FastAPI, etc.
+- `databases` - PostgreSQL, MongoDB, Redis, etc.
+- `cloud` - AWS, Azure, GCP, etc.
+- `devops` - Docker, Kubernetes, Terraform, etc.
+- `messaging` - RabbitMQ, Kafka, etc.
+- `ai` - PyTorch, OpenAI, Anthropic, etc.
+- `enterprise` - SAP, Salesforce, etc.
+- `patterns` - Microservices, CQRS, DDD, etc.
+- `apis` - Binance, Stripe, Twilio, etc.
+- `testing` - Jest, Cypress, Playwright, etc.
+- `mobile` - React Native, Flutter, Swift, etc.
+- `styling` - TailwindCSS, Sass, Bootstrap, etc.
+
+---
+
+### ProjectData/projects.json
+
+**Entities**: `Project`, `ProjectPage`, `ProjectFeature`, `ProjectTechnology`
+**Records**: 3 projects with nested data
+
+```json
+{
+ "title": "Project Name",
+ "description": "...",
+ "status": "Featured",
+ "imageUrl": "/Assets/Projects/...",
+ "repoUrl": "https://github.com/...",
+ "demoUrl": "",
+ "technologies": ["React", "TypeScript", ...],
+ "features": [
+ {
+ "title": "Feature Name",
+ "description": "...",
+ "icon": "font-awesome-icon-name"
+ }
+ ],
+ "pages": [
+ {
+ "title": "Overview",
+ "type": "OVERVIEW",
+ "navOrder": 1,
+ "content": "## Markdown content..."
+ }
+ ]
+}
+```
+
+---
+
+## Adding New Seed Data
+
+1. Create JSON file in appropriate folder
+2. Follow existing schema patterns
+3. Create corresponding seeder in `../seeds/seeders/`
+4. Update seeder barrel exports
+5. Add to orchestrator in `../seeds/seed.ts`
+
+## Asset References
+
+Image URLs in seed data should reference files in:
+- `/Assets/Projects/{ProjectName}/` - Project images
+- `/Assets/Site/` - Site-wide assets (logo, favicon)
+
+These are served statically by the backend at runtime.
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/context/db-context.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/context/db-context.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c68a0cc60c30ee6f3f7a41765c0e8501b64e43dd
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/context/db-context.ts
@@ -0,0 +1,12 @@
+import { AppDataSource } from '../../config/database';
+
+export const initializeDatabase = async () => {
+ try {
+ await AppDataSource.initialize();
+ console.log('Data Source has been initialized!');
+ } catch (err) {
+ console.error('Error during Data Source initialization:', err);
+ process.exit(1);
+ }
+};
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/ai-settings.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/ai-settings.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..294ae8ff45f70223054bbd0c4afad72e73238d2b
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/ai-settings.entity.ts
@@ -0,0 +1,133 @@
+/**
+ * @fileoverview AI Settings Entity
+ * Stores AI provider configuration with encrypted API key storage.
+ *
+ * @module entities/ai-settings
+ * @author Armand Richelet-Kleinberg
+ * @since 1.0.0
+ *
+ * @example
+ * // Creating a new AI settings record
+ * const settings = new AiSettings();
+ * settings.provider = 'openai';
+ * settings.model = 'gpt-4';
+ * settings.apiKeyEncrypted = encrypt(apiKey);
+ * await repository.save(settings);
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+
+/**
+ * Supported AI providers.
+ * @enum {string}
+ */
+export enum AiProvider {
+ /** OpenAI (GPT-3.5, GPT-4) */
+ OPENAI = 'openai',
+ /** Anthropic (Claude) */
+ ANTHROPIC = 'anthropic',
+ /** Google (Gemini) */
+ GOOGLE = 'google',
+ /** Custom/self-hosted API */
+ CUSTOM = 'custom'
+}
+
+/**
+ * AI Settings entity for storing provider configuration.
+ *
+ * @class AiSettings
+ * @description Stores AI configuration including provider, model, and encrypted API key.
+ * Only one active configuration is used at a time.
+ *
+ * @remarks
+ * - API keys are stored encrypted using AES-256-GCM
+ * - Temperature and maxTokens control response generation
+ * - Use the AiService to manage settings with encryption handling
+ *
+ * @see {@link AiService} for configuration management
+ * @see {@link encrypt} for API key encryption
+ */
+@Entity('ai_settings')
+export class AiSettings {
+ /**
+ * Unique identifier for the settings record.
+ * @type {number}
+ */
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ /**
+ * AI provider identifier.
+ * @type {string}
+ * @default 'openai'
+ * @example 'openai', 'anthropic', 'google', 'custom'
+ */
+ @Column({ length: 50, default: 'openai' })
+ provider!: string;
+
+ /**
+ * Custom API URL for self-hosted or alternative endpoints.
+ * @type {string | null}
+ * @remarks Only used when provider is 'custom' or for proxy setups
+ */
+ @Column({ length: 500, nullable: true })
+ apiUrl!: string;
+
+ /**
+ * Encrypted API key for the provider.
+ * @type {string | null}
+ * @remarks Encrypted using AES-256-GCM via encryption utility
+ * @see {@link encrypt} for encryption details
+ */
+ @Column('text', { nullable: true })
+ apiKeyEncrypted!: string;
+
+ /**
+ * Model identifier to use.
+ * @type {string}
+ * @default 'gpt-4'
+ * @example 'gpt-4', 'gpt-3.5-turbo', 'claude-3-opus', 'gemini-pro'
+ */
+ @Column({ length: 100, default: 'gpt-4' })
+ model!: string;
+
+ /**
+ * Sampling temperature for response generation.
+ * @type {number}
+ * @default 0.7
+ * @remarks Range: 0.0 (deterministic) to 2.0 (creative)
+ */
+ @Column({ type: 'decimal', precision: 3, scale: 2, default: 0.7 })
+ temperature!: number;
+
+ /**
+ * Maximum tokens in the response.
+ * @type {number}
+ * @default 2000
+ */
+ @Column({ type: 'integer', default: 2000 })
+ maxTokens!: number;
+
+ /**
+ * Whether this configuration is currently active.
+ * @type {boolean}
+ * @default true
+ */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ /**
+ * Record creation timestamp.
+ * @type {Date}
+ */
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Record last update timestamp.
+ * @type {Date}
+ */
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/audit-log.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/audit-log.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c0aeaf921130b18ebce6c32f5a4ef293941d8666
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/audit-log.entity.ts
@@ -0,0 +1,78 @@
+/**
+ * @fileoverview Audit Log Entity
+ * Stores security-relevant events for compliance and monitoring.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ ManyToOne,
+ JoinColumn,
+ Index
+} from 'typeorm';
+import { User } from './user.entity';
+import { AuditAction } from '@arkalliance/startupcms-ai-share';
+
+/**
+ * AuditLog entity for security event tracking.
+ * @remarks
+ * - Logs authentication, role changes, and security events
+ * - userId is nullable for failed login attempts
+ * - Indexed for efficient querying by user and action
+ */
+@Entity('audit_logs')
+@Index(['userId', 'createdAt'])
+@Index(['action', 'createdAt'])
+export class AuditLog {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ /** User who performed the action (null for failed logins with non-existent user) */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @ManyToOne(() => User, { nullable: true, onDelete: 'SET NULL' })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+
+ /** Type of action performed (stored as string for SQLite compatibility) */
+ @Column({ type: 'varchar', length: 50 })
+ action!: AuditAction;
+
+ /** Client IP address */
+ @Column({ length: 45, nullable: true })
+ ipAddress?: string;
+
+ /** Browser/device user agent */
+ @Column({ length: 500, nullable: true })
+ userAgent?: string;
+
+ /** Whether the action succeeded */
+ @Column({ default: true })
+ success!: boolean;
+
+ /** Additional context as JSON string */
+ @Column('text', { nullable: true })
+ details?: string;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Parse details JSON if present.
+ */
+ get parsedDetails(): Record | null {
+ if (!this.details) return null;
+ try {
+ return JSON.parse(this.details);
+ } catch {
+ return null;
+ }
+ }
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/business-domain.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/business-domain.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..5320edab461ea3205cac889fc29ee2c063c2c80d
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/business-domain.entity.ts
@@ -0,0 +1,100 @@
+/**
+ * @fileoverview Business Domain Entity
+ * Represents business domain knowledge and expertise.
+ * Supports userId (new) and legacy profileId/collaboratorId.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Index } from 'typeorm';
+import { User } from './user.entity';
+import { Collaborator } from './collaborator.entity';
+
+/**
+ * Preset list of valid business domains.
+ * Backend validation should enforce values from this list.
+ */
+export const BUSINESS_DOMAIN_PRESETS = [
+ 'Logistics',
+ 'Finance',
+ 'Trading',
+ 'Insurance',
+ 'Steel Manufacturing',
+ 'Theatre',
+ 'Entertainment',
+ 'Music Playing',
+ 'Music Composing',
+ 'Movie Making',
+ 'Retail',
+ 'Banking',
+ 'Asset Management',
+ 'Supply Chain',
+ 'Healthcare',
+ 'E-Commerce',
+ 'Telecommunications',
+ 'Real Estate',
+ 'Energy',
+ 'Automotive'
+] as const;
+
+export type BusinessDomainType = typeof BUSINESS_DOMAIN_PRESETS[number];
+
+@Entity('business_domains')
+@Index('IDX_business_domains_userId', ['userId'])
+@Index('IDX_business_domains_displayOrder', ['displayOrder'])
+export class BusinessDomain {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ /**
+ * Domain name - must be from preset list.
+ */
+ @Column({ length: 100 })
+ domain!: string;
+
+ /**
+ * Proficiency level in this domain.
+ * @example 'Expert', 'Advanced', 'Intermediate', 'Beginner'
+ */
+ @Column({ length: 50, nullable: true })
+ level!: string;
+
+ @Column('text', { nullable: true })
+ description!: string;
+
+ /**
+ * Years of experience in this domain.
+ */
+ @Column({ type: 'int', nullable: true })
+ yearsOfExperience!: number;
+
+ /**
+ * Lucide icon name for visual representation.
+ */
+ @Column({ length: 50, nullable: true })
+ icon!: string;
+
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /** @deprecated Use userId instead */
+ @Column({ default: 1 })
+ profileId!: number;
+
+ /** @deprecated Use userId instead - kept for migration */
+ @Column('uuid', { nullable: true })
+ collaboratorId?: string;
+
+ @ManyToOne(() => Collaborator, collaborator => collaborator.businessDomains, { nullable: true })
+ @JoinColumn({ name: 'collaboratorId' })
+ collaborator?: Collaborator;
+
+ /** User who owns this business domain (for personal resume) */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @ManyToOne(() => User, user => user.businessDomains, { nullable: true })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/carousel-item.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/carousel-item.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d4e2c4c2e3a28b113deb0b473719c1494de46763
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/carousel-item.entity.ts
@@ -0,0 +1,48 @@
+/**
+ * @fileoverview Carousel Item Entity
+ * Represents a slide in the homepage carousel.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+
+@Entity('carousel_items')
+export class CarouselItem {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column()
+ title!: string;
+
+ @Column({ nullable: true })
+ subtitle!: string;
+
+ @Column({ type: 'text', nullable: true })
+ description!: string;
+
+ @Column()
+ imageUrl!: string;
+
+ @Column({ nullable: true })
+ linkUrl!: string;
+
+ @Column({ nullable: true })
+ linkText!: string;
+
+ @Column({ default: 0 })
+ order!: number;
+
+ @Column({ default: true })
+ isActive!: boolean;
+
+ @Column({ nullable: true })
+ projectId!: string;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/collaborator.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/collaborator.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c2838ba3e19a6728e6f6f4cffbad7e2f4367e87a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/collaborator.entity.ts
@@ -0,0 +1,173 @@
+/**
+ * @fileoverview Collaborator Entity
+ * Represents a team member in an organization with hierarchical structure.
+ * Evolves from the original Profile entity with added hierarchy support.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn,
+ ManyToOne,
+ OneToMany,
+ OneToOne,
+ JoinColumn,
+ Index
+} from 'typeorm';
+import { Organization } from './organization.entity';
+import { User } from './user.entity';
+import { Experience } from './experience.entity';
+import { Education } from './education.entity';
+import { Skill } from './skill.entity';
+import { Language } from './language.entity';
+import { Hobby } from './hobby.entity';
+import { BusinessDomain } from './business-domain.entity';
+
+/**
+ * Collaborator entity for organization team members.
+ * @remarks
+ * - Supports hierarchy via self-referential reportsTo relationship
+ * - Optionally linked to User for authentication
+ * - Owns resume data (experiences, education, skills, etc.)
+ */
+@Entity('collaborators')
+export class Collaborator {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column({ length: 100 })
+ firstName!: string;
+
+ @Column({ length: 100 })
+ lastName!: string;
+
+ @Column({ length: 200, nullable: true })
+ email?: string;
+
+ /** Job title/position */
+ @Column({ length: 200 })
+ position!: string;
+
+ /** Department or team */
+ @Column({ length: 100, nullable: true })
+ department?: string;
+
+ /** Bio/overview text */
+ @Column('text', { nullable: true })
+ bio?: string;
+
+ @Column({ length: 500, nullable: true })
+ avatarUrl?: string;
+
+ @Column({ length: 255, nullable: true })
+ linkedinUrl?: string;
+
+ @Column({ length: 255, nullable: true })
+ githubUrl?: string;
+
+ @Column({ length: 255, nullable: true })
+ twitterUrl?: string;
+
+ @Column({ length: 50, nullable: true })
+ phone?: string;
+
+ /** Date when collaborator joined */
+ @Column({ type: 'date', nullable: true })
+ hireDate?: Date;
+
+ /** Whether collaborator is currently active */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ /** Display order in lists */
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+
+ // ============================================
+ // Organization Relationship
+ // ============================================
+
+ @Index()
+ @Column('uuid')
+ organizationId!: string;
+
+ @ManyToOne(() => Organization, org => org.collaborators)
+ @JoinColumn({ name: 'organizationId' })
+ organization!: Organization;
+
+ // ============================================
+ // Hierarchy (Self-Reference)
+ // ============================================
+
+ /** ID of the manager this person reports to */
+ @Index()
+ @Column('uuid', { nullable: true })
+ reportsToId?: string;
+
+ @ManyToOne(() => Collaborator, collaborator => collaborator.directReports, { nullable: true })
+ @JoinColumn({ name: 'reportsToId' })
+ reportsTo?: Collaborator;
+
+ @OneToMany(() => Collaborator, collaborator => collaborator.reportsTo)
+ directReports!: Collaborator[];
+
+ // ============================================
+ // User Authentication Link (Optional)
+ // ============================================
+
+ /** Linked user account for authentication */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @OneToOne(() => User, { nullable: true })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+
+ // ============================================
+ // Resume Data Relations
+ // ============================================
+
+ @OneToMany(() => Experience, experience => experience.collaborator)
+ experiences!: Experience[];
+
+ @OneToMany(() => Education, education => education.collaborator)
+ educations!: Education[];
+
+ @OneToMany(() => Skill, skill => skill.collaborator)
+ skills!: Skill[];
+
+ @OneToMany(() => Language, language => language.collaborator)
+ languages!: Language[];
+
+ @OneToMany(() => Hobby, hobby => hobby.collaborator)
+ hobbies!: Hobby[];
+
+ @OneToMany(() => BusinessDomain, domain => domain.collaborator)
+ businessDomains!: BusinessDomain[];
+
+ // ============================================
+ // Tasks / Accomplishments (Recognition System)
+ // ============================================
+
+ @OneToMany('Task', 'collaborator')
+ tasks!: import('./task.entity').Task[];
+
+ // ============================================
+ // Computed Properties
+ // ============================================
+
+ /** Full name for display */
+ get fullName(): string {
+ return `${this.firstName} ${this.lastName}`;
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/education.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/education.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fd0352ddc9a9ae0e8e13f593b22932cb47b32cf7
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/education.entity.ts
@@ -0,0 +1,60 @@
+/**
+ * @fileoverview Education Entity
+ * Supports userId (new) and legacy profileId/collaboratorId.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Index } from 'typeorm';
+import { User } from './user.entity';
+import { Collaborator } from './collaborator.entity';
+
+@Entity('education')
+@Index('IDX_education_userId', ['userId'])
+export class Education {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({ length: 200 })
+ institution!: string;
+
+ @Column({ length: 100, nullable: true })
+ degree!: string;
+
+ @Column({ length: 100, nullable: true })
+ fieldOfStudy!: string;
+
+ @Column({ type: 'date', nullable: true })
+ startDate!: Date;
+
+ @Column({ type: 'date', nullable: true })
+ endDate!: Date;
+
+ @Column('text', { nullable: true })
+ description!: string;
+
+ /** @deprecated Use userId instead */
+ @Column({ default: 1 })
+ profileId!: number;
+
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /** @deprecated Use userId instead - kept for migration */
+ @Column('uuid', { nullable: true })
+ collaboratorId?: string;
+
+ @ManyToOne(() => Collaborator, collaborator => collaborator.educations, { nullable: true })
+ @JoinColumn({ name: 'collaboratorId' })
+ collaborator?: Collaborator;
+
+ /** User who owns this education (for personal resume) */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @ManyToOne(() => User, user => user.educations, { nullable: true })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/experience.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/experience.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3104e3580a2ad7302df6d22c8df1dd6e56e68f1b
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/experience.entity.ts
@@ -0,0 +1,68 @@
+/**
+ * @fileoverview Experience Entity
+ * Updated with all required fields for CV management.
+ * Supports userId (new) and legacy profileId/collaboratorId.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Index } from 'typeorm';
+import { User } from './user.entity';
+import { Collaborator } from './collaborator.entity';
+
+@Entity('experience')
+@Index('IDX_experience_userId', ['userId'])
+@Index('IDX_experience_displayOrder', ['displayOrder'])
+export class Experience {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({ length: 200 })
+ company!: string;
+
+ @Column({ length: 100 })
+ position!: string;
+
+ @Column({ length: 200, nullable: true })
+ project!: string;
+
+ @Column({ type: 'date', nullable: true })
+ startDate!: Date;
+
+ @Column({ type: 'date', nullable: true })
+ endDate!: Date | null;
+
+ @Column('text', { nullable: true })
+ description!: string;
+
+ @Column('simple-array', { nullable: true })
+ technologies!: string[];
+
+ @Column({ default: false })
+ isHighlighted!: boolean;
+
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /** @deprecated Use userId instead */
+ @Column({ default: 1 })
+ profileId!: number;
+
+ /** @deprecated Use userId instead - kept for migration */
+ @Column('uuid', { nullable: true })
+ collaboratorId?: string;
+
+ @ManyToOne(() => Collaborator, collaborator => collaborator.experiences, { nullable: true })
+ @JoinColumn({ name: 'collaboratorId' })
+ collaborator?: Collaborator;
+
+ /** User who owns this experience (for personal resume) */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @ManyToOne(() => User, user => user.experiences, { nullable: true })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/hobby.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/hobby.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..33c9a7ac699666de4aac2f5b75c17adce723b55a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/hobby.entity.ts
@@ -0,0 +1,56 @@
+/**
+ * @fileoverview Hobby Entity
+ * Represents personal hobbies and interests.
+ * Supports userId (new) and legacy profileId/collaboratorId.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Index } from 'typeorm';
+import { User } from './user.entity';
+import { Collaborator } from './collaborator.entity';
+
+@Entity('hobbies')
+@Index('IDX_hobbies_userId', ['userId'])
+@Index('IDX_hobbies_displayOrder', ['displayOrder'])
+export class Hobby {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({ length: 100 })
+ name!: string;
+
+ @Column('text', { nullable: true })
+ description!: string;
+
+ /**
+ * Lucide icon name for visual representation.
+ * @example 'Music', 'Camera', 'Gamepad2'
+ */
+ @Column({ length: 50, nullable: true })
+ icon!: string;
+
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /** @deprecated Use userId instead */
+ @Column({ default: 1 })
+ profileId!: number;
+
+ /** @deprecated Use userId instead - kept for migration */
+ @Column('uuid', { nullable: true })
+ collaboratorId?: string;
+
+ @ManyToOne(() => Collaborator, collaborator => collaborator.hobbies, { nullable: true })
+ @JoinColumn({ name: 'collaboratorId' })
+ collaborator?: Collaborator;
+
+ /** User who owns this hobby (for personal resume) */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @ManyToOne(() => User, user => user.hobbies, { nullable: true })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/language.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/language.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..36704bb76cfd0be4f4a928a876f3ab18504dd694
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/language.entity.ts
@@ -0,0 +1,67 @@
+/**
+ * @fileoverview Language Entity
+ * Represents language proficiency with three dimensions.
+ * Supports userId (new) and legacy profileId/collaboratorId.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Index } from 'typeorm';
+import { User } from './user.entity';
+import { Collaborator } from './collaborator.entity';
+
+@Entity('languages')
+@Index('IDX_languages_userId', ['userId'])
+@Index('IDX_languages_displayOrder', ['displayOrder'])
+export class Language {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({ length: 100 })
+ language!: string;
+
+ /**
+ * Speaking proficiency (1-5 scale)
+ * 1 = Basic, 5 = Native/Fluent
+ */
+ @Column({ type: 'int', default: 1 })
+ speaking!: number;
+
+ /**
+ * Writing proficiency (1-5 scale)
+ * 1 = Basic, 5 = Native/Fluent
+ */
+ @Column({ type: 'int', default: 1 })
+ writing!: number;
+
+ /**
+ * Presenting proficiency (1-5 scale)
+ * 1 = Basic, 5 = Native/Fluent
+ */
+ @Column({ type: 'int', default: 1 })
+ presenting!: number;
+
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /** @deprecated Use userId instead */
+ @Column({ default: 1 })
+ profileId!: number;
+
+ /** @deprecated Use userId instead - kept for migration */
+ @Column('uuid', { nullable: true })
+ collaboratorId?: string;
+
+ @ManyToOne(() => Collaborator, collaborator => collaborator.languages, { nullable: true })
+ @JoinColumn({ name: 'collaboratorId' })
+ collaborator?: Collaborator;
+
+ /** User who owns this language (for personal resume) */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @ManyToOne(() => User, user => user.languages, { nullable: true })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/media.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/media.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6db5681741f0e4321d5dd1def1d2b6ad17401c2a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/media.entity.ts
@@ -0,0 +1,220 @@
+/**
+ * @fileoverview Media Entity
+ * Stores uploaded media files with comprehensive metadata for widgets and AI integration.
+ *
+ * @module entities/media
+ * @author Armand Richelet-Kleinberg
+ * @since 1.0.0
+ *
+ * @description
+ * The Media entity supports multiple file types including images, videos, audio,
+ * documents (PDF, Word, Excel), and data files (JSON, Markdown). Each media item
+ * can be assigned a unique key for programmatic reference in widgets or AI context.
+ *
+ * @example
+ * // Creating a new media record from upload
+ * const media = new Media();
+ * media.name = 'Company Logo';
+ * media.key = 'logo-main';
+ * media.url = '/uploads/image/uuid-filename.png';
+ * media.type = MediaType.IMAGE;
+ * media.mimeType = 'image/png';
+ * media.tags = ['branding', 'logo'];
+ * await repository.save(media);
+ *
+ * @example
+ * // Using key to reference media in widgets
+ * const logo = await mediaRepo.findOne({ where: { key: 'logo-main' } });
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+
+/**
+ * Media asset types supported by the system.
+ *
+ * @enum {string}
+ * @description Used to categorize uploaded files for filtering and display purposes.
+ */
+export enum MediaType {
+ /** Image files - JPEG, PNG, GIF, WebP, SVG, ICO */
+ IMAGE = 'image',
+ /** Video files - MP4, WebM, MOV, AVI */
+ VIDEO = 'video',
+ /** Audio files - MP3, WAV, OGG, FLAC */
+ AUDIO = 'audio',
+ /** PDF documents */
+ PDF = 'pdf',
+ /** Microsoft Word documents - DOC, DOCX */
+ WORD = 'word',
+ /** Microsoft Excel spreadsheets - XLS, XLSX */
+ EXCEL = 'excel',
+ /** Markdown text files - MD */
+ MARKDOWN = 'markdown',
+ /** JSON data files */
+ JSON = 'json',
+ /** Other unclassified document types */
+ OTHER = 'other'
+}
+
+/**
+ * Media entity for storing uploaded files and external media references.
+ *
+ * @class Media
+ * @description Stores media files with rich metadata including dimensions, tags,
+ * and custom metadata for AI assistant integration.
+ *
+ * @remarks
+ * - Use `key` for stable programmatic references (survives re-uploads)
+ * - Use `tags` for categorization and filtering
+ * - Use `metadata` for AI context or widget-specific configuration
+ * - Files are stored locally in type-organized subdirectories
+ *
+ * @see {@link AdminMediaService} for CRUD operations
+ * @see {@link upload.middleware} for file upload handling
+ */
+@Entity('media')
+export class Media {
+ /**
+ * Unique identifier (UUID) for the media record.
+ * @type {string}
+ * @remarks Auto-generated UUID v4
+ */
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ /**
+ * Human-readable display name.
+ * @type {string}
+ * @example 'Company Logo', 'Profile Photo', 'Product Brochure'
+ */
+ @Column({ length: 200 })
+ name!: string;
+
+ /**
+ * Unique key for programmatic reference.
+ * @type {string | null}
+ * @example 'profile-avatar', 'cv-document', 'hero-banner'
+ * @remarks
+ * - Optional but recommended for media used in widgets or AI context
+ * - Must be unique across all media items
+ * - Use kebab-case for consistency
+ */
+ @Column({ length: 100, unique: true, nullable: true })
+ key!: string;
+
+ /**
+ * Full URL or relative path to the media file.
+ * @type {string}
+ * @example '/uploads/image/abc123-photo.jpg'
+ * @example 'https://example.com/image.png'
+ */
+ @Column({ length: 500 })
+ url!: string;
+
+ /**
+ * Media type classification.
+ * @type {MediaType}
+ * @default MediaType.IMAGE
+ * @see MediaType for available types
+ */
+ @Column({ type: 'text', default: MediaType.IMAGE })
+ type!: MediaType;
+
+ /**
+ * MIME type of the file.
+ * @type {string | null}
+ * @example 'image/jpeg', 'application/pdf', 'video/mp4'
+ */
+ @Column({ length: 100, nullable: true })
+ mimeType!: string;
+
+ /**
+ * Original filename as uploaded by user.
+ * @type {string | null}
+ * @remarks Preserved for reference; actual stored filename may differ
+ */
+ @Column({ length: 255, nullable: true })
+ originalFileName!: string;
+
+ /**
+ * File size in bytes.
+ * @type {number}
+ * @default 0
+ */
+ @Column({ type: 'integer', default: 0 })
+ fileSize!: number;
+
+ /**
+ * Alt text for accessibility.
+ * @type {string | null}
+ * @remarks Required for images per WCAG guidelines
+ */
+ @Column({ length: 500, nullable: true })
+ altText!: string;
+
+ /**
+ * Description or caption for the media.
+ * @type {string | null}
+ * @remarks Can be used for AI context or display purposes
+ */
+ @Column('text', { nullable: true })
+ description!: string;
+
+ /**
+ * Tags for categorization and filtering.
+ * @type {string[]}
+ * @example ['branding', 'logo'], ['documentation', 'api']
+ * @remarks Stored as JSON array
+ */
+ @Column('simple-json', { nullable: true })
+ tags!: string[];
+
+ /**
+ * Additional metadata for AI/widget integration.
+ * @type {Record}
+ * @example { aiContext: 'company info', widgetId: 'header' }
+ * @remarks Flexible JSON storage for custom data
+ */
+ @Column('simple-json', { nullable: true })
+ metadata!: Record;
+
+ /**
+ * Width of image/video in pixels.
+ * @type {number | null}
+ * @remarks Only applicable for visual media
+ */
+ @Column({ type: 'integer', nullable: true })
+ width!: number;
+
+ /**
+ * Height of image/video in pixels.
+ * @type {number | null}
+ * @remarks Only applicable for visual media
+ */
+ @Column({ type: 'integer', nullable: true })
+ height!: number;
+
+ /**
+ * Whether the media is publicly accessible.
+ * @type {boolean}
+ * @default true
+ * @remarks Set to false for private/draft media
+ */
+ @Column({ default: true })
+ isPublic!: boolean;
+
+ /**
+ * Record creation timestamp.
+ * @type {Date}
+ */
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Record last update timestamp.
+ * @type {Date}
+ */
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/menu-item.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/menu-item.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b7f3935767edca6ddbae37a56f9662efe3e82d7c
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/menu-item.entity.ts
@@ -0,0 +1,59 @@
+/**
+ * @fileoverview Menu Item Entity
+ * Represents a navigation menu item in the database.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, OneToMany, JoinColumn } from 'typeorm';
+import { MenuPositionEnum } from '@arkalliance/startupcms-ai-share';
+
+@Entity('menu_items')
+export class MenuItem {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column()
+ label!: string;
+
+ @Column({ nullable: true })
+ icon!: string;
+
+ @Column()
+ route!: string;
+
+ @Column({
+ type: 'simple-enum',
+ enum: MenuPositionEnum,
+ default: MenuPositionEnum.HEADER
+ })
+ position!: MenuPositionEnum;
+
+ @Column({ default: 0 })
+ order!: number;
+
+ @Column({ default: true })
+ isVisible!: boolean;
+
+ @Column({ default: false })
+ openInNewTab!: boolean;
+
+ @ManyToOne(() => MenuItem, item => item.children, { nullable: true, onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'parentId' })
+ parent!: MenuItem;
+
+ @Column({ nullable: true })
+ parentId!: number;
+
+ @OneToMany(() => MenuItem, item => item.parent)
+ children!: MenuItem[];
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/organization.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/organization.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bc5fb711d9290272fb1bf39eb54e5f679d5596b5
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/organization.entity.ts
@@ -0,0 +1,118 @@
+/**
+ * @fileoverview Organization Entity
+ * Represents a company/organization in the corporate portfolio.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn,
+ OneToMany
+} from 'typeorm';
+import { Collaborator } from './collaborator.entity';
+
+/**
+ * Organization entity for company/organization data.
+ * @remarks
+ * - Stores company profile, location, and branding
+ * - One organization can have many collaborators
+ * - Default organization is created during seeding
+ */
+@Entity('organizations')
+export class Organization {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ /** Organization display name */
+ @Column({ length: 200 })
+ name!: string;
+
+ /** Legal/registered business name */
+ @Column({ length: 300, nullable: true })
+ legalName?: string;
+
+ /** Short tagline/slogan */
+ @Column({ length: 300, nullable: true })
+ tagline?: string;
+
+ /** Mission statement */
+ @Column('text', { nullable: true })
+ mission?: string;
+
+ /** Vision statement */
+ @Column('text', { nullable: true })
+ vision?: string;
+
+ /** Full description */
+ @Column('text', { nullable: true })
+ description?: string;
+
+ /** Logo image URL */
+ @Column({ length: 500, nullable: true })
+ logoUrl?: string;
+
+ /** Icon/favicon URL */
+ @Column({ length: 500, nullable: true })
+ iconUrl?: string;
+
+ // Location
+ @Column({ length: 300, nullable: true })
+ address?: string;
+
+ @Column({ length: 100, nullable: true })
+ city?: string;
+
+ @Column({ length: 100, nullable: true })
+ country?: string;
+
+ @Column({ length: 20, nullable: true })
+ postalCode?: string;
+
+ @Column({ length: 50, nullable: true })
+ timezone?: string;
+
+ /** GPS Latitude */
+ @Column('decimal', { precision: 10, scale: 8, nullable: true })
+ latitude?: number;
+
+ /** GPS Longitude */
+ @Column('decimal', { precision: 11, scale: 8, nullable: true })
+ longitude?: number;
+
+ // Social Links (stored as JSON for flexibility)
+ @Column('simple-json', { nullable: true })
+ socialLinks?: {
+ website?: string;
+ linkedIn?: string;
+ twitter?: string;
+ github?: string;
+ youtube?: string;
+ instagram?: string;
+ };
+
+ /** Year company was founded */
+ @Column({ nullable: true })
+ foundedYear?: number;
+
+ /** Number of employees (for display) */
+ @Column({ nullable: true })
+ employeeCount?: number;
+
+ /** Whether organization is active */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+
+ // Relations
+ @OneToMany(() => Collaborator, collaborator => collaborator.organization)
+ collaborators!: Collaborator[];
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/outbox.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/outbox.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8b39357b57299cd832b0770cff98ceda72eba7e8
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/outbox.entity.ts
@@ -0,0 +1,19 @@
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm';
+
+@Entity('outbox')
+export class Outbox {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column()
+ type!: string;
+
+ @Column('simple-json')
+ payload!: any;
+
+ @CreateDateColumn()
+ elementCreatedAt!: Date;
+
+ @Column({ default: false })
+ processed!: boolean;
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/page-definition.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/page-definition.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a37dd0ca814fb578047e9deaf2d08e01fb26b931
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/page-definition.entity.ts
@@ -0,0 +1,47 @@
+/**
+ * @fileoverview Page Definition Entity
+ * Represents configurable page definitions for static export.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+import { StaticPageType } from '@arkalliance/startupcms-ai-share';
+
+@Entity('page_definition')
+export class PageDefinition {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({
+ type: 'simple-enum',
+ enum: StaticPageType
+ })
+ pageType!: StaticPageType;
+
+ @Column()
+ title!: string;
+
+ @Column()
+ route!: string;
+
+ @Column('simple-json', { nullable: true })
+ sections!: string[] | null;
+
+ @Column({ default: true })
+ isEnabled!: boolean;
+
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ @Column('simple-json', { nullable: true })
+ metadata!: Record | null;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/page.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/page.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3f905eae0e01e86e3f608acde967327cd6a213df
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/page.entity.ts
@@ -0,0 +1,115 @@
+/**
+ * @fileoverview Page Entity - Core CMS page with SEO configuration
+ * @description Dynamic page entity for SEO-optimized content management.
+ * Supports multiple page types (home, about, blog, project, custom) with
+ * full SEO metadata and structured data relationships.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn,
+ ManyToOne,
+ OneToOne,
+ OneToMany,
+ JoinColumn,
+ Index
+} from 'typeorm';
+import { User } from './user.entity';
+import { SeoMeta } from './seo-meta.entity';
+import { StructuredData } from './structured-data.entity';
+
+/**
+ * Page type enumeration for content categorization
+ */
+export enum PageType {
+ HOME = 'home',
+ ABOUT = 'about',
+ BLOG = 'blog',
+ PROJECT = 'project',
+ TEAM = 'team',
+ CONTACT = 'contact',
+ CUSTOM = 'custom'
+}
+
+/**
+ * Page entity for dynamic CMS content
+ * @remarks
+ * - Supports SEO metadata via SeoMeta relation
+ * - Multiple structured data schemas per page
+ * - Markdown/HTML content support
+ * - Author tracking for content attribution
+ */
+@Entity('pages')
+export class Page {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ /** URL-friendly slug (unique) */
+ @Column({ unique: true, length: 255 })
+ @Index('IDX_page_slug')
+ slug!: string;
+
+ /** Page title */
+ @Column({ length: 255 })
+ title!: string;
+
+ /** Page content (Markdown or HTML) */
+ @Column('text')
+ content!: string;
+
+ /** Page type for template selection */
+ @Column({
+ type: 'varchar',
+ length: 50,
+ default: PageType.CUSTOM
+ })
+ @Index('IDX_page_type')
+ pageType!: PageType;
+
+ /** Publication status */
+ @Column({ default: false })
+ @Index('IDX_page_published')
+ isPublished!: boolean;
+
+ /** Publication date */
+ @Column({ nullable: true })
+ publishedAt?: Date;
+
+ /** Author user ID */
+ @Column('uuid', { nullable: true })
+ authorId?: string;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+
+ // ============================================
+ // Relations
+ // ============================================
+
+ /** Page author */
+ @ManyToOne(() => User, { nullable: true })
+ @JoinColumn({ name: 'authorId' })
+ author?: User;
+
+ /** SEO metadata (1:1 relationship) */
+ @OneToOne(() => SeoMeta, seoMeta => seoMeta.page, {
+ cascade: true,
+ eager: true
+ })
+ seoMeta?: SeoMeta;
+
+ /** Structured data schemas (1:many relationship) */
+ @OneToMany(() => StructuredData, structuredData => structuredData.page, {
+ cascade: true,
+ eager: true
+ })
+ structuredData?: StructuredData[];
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/profile.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/profile.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2b164af55dd145b282f55f6583a9053adcfe433d
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/profile.entity.ts
@@ -0,0 +1,38 @@
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+
+@Entity('profiles')
+export class Profile {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({ length: 100 })
+ firstName!: string;
+
+ @Column({ length: 100 })
+ lastName!: string;
+
+ @Column({ length: 200, nullable: true })
+ title!: string;
+
+ @Column('text', { nullable: true })
+ overview!: string;
+
+ @Column({ length: 200 })
+ email!: string;
+
+ @Column({ length: 255, nullable: true })
+ linkedinUrl!: string;
+
+ @Column({ length: 255, nullable: true })
+ githubUrl!: string;
+
+ @Column({ length: 255, nullable: true })
+ avatarUrl!: string;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-controller.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-controller.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3fa5ca723b9614f93bbf12afdd5081084a753f60
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-controller.entity.ts
@@ -0,0 +1,26 @@
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
+import { Project } from './project.entity';
+import { ProjectEndpoint } from './project-endpoint.entity';
+
+@Entity('project_controllers')
+export class ProjectController {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column()
+ name!: string;
+
+ @Column()
+ basePath!: string;
+
+ @Column({ nullable: true })
+ description!: string;
+
+ @ManyToOne(() => Project, project => project.controllers, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'project_id' })
+ project!: Project;
+
+ @OneToMany(() => ProjectEndpoint, endpoint => endpoint.controller, { cascade: true })
+ endpoints!: ProjectEndpoint[];
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-endpoint.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-endpoint.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f02972e945a8c93659aea9f9683693b3558d73b2
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-endpoint.entity.ts
@@ -0,0 +1,22 @@
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
+import { ProjectController } from './project-controller.entity';
+
+@Entity('project_endpoints')
+export class ProjectEndpoint {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column()
+ method!: string;
+
+ @Column()
+ path!: string;
+
+ @Column({ nullable: true })
+ description!: string;
+
+ @ManyToOne(() => ProjectController, controller => controller.endpoints, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'controller_id' })
+ controller!: ProjectController;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-feature.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-feature.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4d2dd5baa59875ccb4cdd9d50c9dae7800a3e110
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-feature.entity.ts
@@ -0,0 +1,25 @@
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
+import { Project } from './project.entity';
+
+@Entity('project_features')
+export class ProjectFeature {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column()
+ title!: string;
+
+ @Column('text')
+ description!: string;
+
+ @Column({ nullable: true })
+ icon!: string;
+
+ @Column({ nullable: true })
+ imageUrl?: string;
+
+ @ManyToOne(() => Project, project => project.features, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'project_id' })
+ project!: Project;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-page.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-page.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..19f7a98399f23c19a600d3a8e5ebb352e8b6a661
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-page.entity.ts
@@ -0,0 +1,37 @@
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, OneToMany } from 'typeorm';
+import { Project } from './project.entity';
+
+export enum PageType {
+ OVERVIEW = 'OVERVIEW',
+ FUNCTIONAL = 'FUNCTIONAL',
+ TECHNICAL = 'TECHNICAL',
+ ROADMAP = 'ROADMAP',
+ TEAM = 'TEAM',
+ CONTACT = 'CONTACT'
+}
+
+@Entity('project_pages')
+export class ProjectPage {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column()
+ title!: string;
+
+ @Column({
+ type: 'text',
+ default: PageType.OVERVIEW
+ })
+ type!: PageType;
+
+ @Column({ default: 0 })
+ navOrder!: number;
+
+ @Column({ type: 'text', nullable: true })
+ content!: string;
+
+ @ManyToOne(() => Project, project => project.pages, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'project_id' })
+ project!: Project;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-technology.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-technology.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..4c855c0ebb0330e0392080751463dbe441ceb7da
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project-technology.entity.ts
@@ -0,0 +1,16 @@
+import { Entity, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm';
+import { Project } from './project.entity';
+
+@Entity('project_technologies')
+export class ProjectTechnology {
+ @PrimaryColumn('uuid')
+ projectId!: string;
+
+ @PrimaryColumn({ length: 50 })
+ technology!: string;
+
+ @ManyToOne(() => Project, project => project.technologies, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'projectId' })
+ project!: Project;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bcd5fb933bbd9da489a02fdf1c6720654dc8e20f
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/project.entity.ts
@@ -0,0 +1,54 @@
+import { Entity, PrimaryGeneratedColumn, Column, OneToMany, ManyToMany, JoinTable } from 'typeorm';
+import { ProjectTechnology } from './project-technology.entity';
+import { ProjectPage } from './project-page.entity';
+import { ProjectFeature } from './project-feature.entity';
+import { ProjectController } from './project-controller.entity';
+
+@Entity('projects')
+export class Project {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column()
+ title!: string;
+
+ @Column('text')
+ description!: string;
+
+ @Column()
+ status!: string;
+
+ @Column({ default: false })
+ isFeatured!: boolean;
+
+ @Column({ nullable: true })
+ imageUrl!: string;
+
+ @Column({ nullable: true })
+ repoUrl!: string;
+
+ @Column({ nullable: true })
+ demoUrl!: string;
+
+ @Column({ nullable: true })
+ packageUrl!: string;
+
+ @Column({ type: 'date', nullable: true })
+ startDate!: Date;
+
+ @Column({ type: 'date', nullable: true })
+ endDate!: Date;
+
+ @OneToMany(() => ProjectTechnology, pt => pt.project)
+ technologies!: ProjectTechnology[];
+
+ @OneToMany(() => ProjectPage, page => page.project, { cascade: true })
+ pages!: ProjectPage[];
+
+ @OneToMany(() => ProjectFeature, feature => feature.project, { cascade: true })
+ features!: ProjectFeature[];
+
+ @OneToMany(() => ProjectController, controller => controller.project, { cascade: true })
+ controllers!: ProjectController[];
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/prompt-template.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/prompt-template.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f74d2c00ddece1a4d85b0300adedd1af8810bd7c
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/prompt-template.entity.ts
@@ -0,0 +1,103 @@
+/**
+ * @fileoverview PromptTemplate Entity
+ * Stores AI prompt templates for various AI-assisted features.
+ * Enables reusable, configurable prompts for profile generation, resume enhancement, etc.
+ *
+ * @module entities/prompt-template
+ * @author Armand Richelet-Kleinberg
+ * @since 1.0.0
+ *
+ * @example
+ * // Creating a new prompt template
+ * const template = new PromptTemplate();
+ * template.name = 'profile-generation';
+ * template.systemPrompt = 'You are an expert data architect...';
+ * template.clientPromptTemplate = 'Generate profile for {firstName} {lastName}...';
+ * await repository.save(template);
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+
+/**
+ * Prompt Template entity for storing AI prompts.
+ *
+ * @class PromptTemplate
+ * @description Stores reusable AI prompt configurations with system and client templates.
+ * Supports placeholder substitution for dynamic content generation.
+ *
+ * @remarks
+ * - Use unique `name` to identify prompts (e.g., 'profile-generation', 'resume-enhancement')
+ * - `clientPromptTemplate` supports placeholders like {firstName}, {description}, etc.
+ * - `outputFormat` describes expected AI output schema
+ */
+@Entity('prompt_templates')
+export class PromptTemplate {
+ /**
+ * Unique identifier for the prompt template.
+ * @type {number}
+ */
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ /**
+ * Unique name identifier for the prompt.
+ * @type {string}
+ * @example 'profile-generation', 'resume-enhancement', 'task-generation'
+ */
+ @Column({ unique: true, length: 100 })
+ name!: string;
+
+ /**
+ * Human-readable description of the prompt's purpose.
+ * @type {string | null}
+ */
+ @Column('text', { nullable: true })
+ description?: string;
+
+ /**
+ * System prompt with AI instructions and rules.
+ * @type {string}
+ * @remarks Defines AI behavior, output format, and constraints
+ */
+ @Column('text')
+ systemPrompt!: string;
+
+ /**
+ * Client prompt template with placeholders.
+ * @type {string}
+ * @remarks Use {placeholders} for dynamic content substitution
+ * @example 'Generate profile for {firstName} {lastName}. Function: {function}'
+ */
+ @Column('text')
+ clientPromptTemplate!: string;
+
+ /**
+ * Expected output format description or schema.
+ * @type {string | null}
+ * @example 'JSON conforming to UserCollaboratorSchema'
+ */
+ @Column({ length: 500, nullable: true })
+ outputFormat?: string;
+
+ /**
+ * Whether this prompt template is active.
+ * @type {boolean}
+ * @default true
+ */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ /**
+ * Record creation timestamp.
+ * @type {Date}
+ */
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Record last update timestamp.
+ * @type {Date}
+ */
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/refresh-token.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/refresh-token.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e07f514d3f25f091151ed70aa51c0417e9c213e9
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/refresh-token.entity.ts
@@ -0,0 +1,66 @@
+/**
+ * @fileoverview Refresh Token Entity
+ * Stores refresh tokens for JWT token rotation.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ ManyToOne,
+ JoinColumn
+} from 'typeorm';
+import { User } from './user.entity';
+
+/**
+ * RefreshToken entity for secure token management.
+ * @remarks
+ * - Stores hash of token, not the token itself
+ * - Supports token rotation (revoke old on use)
+ * - Tracks device info for session management
+ */
+@Entity('refresh_tokens')
+export class RefreshToken {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column('uuid')
+ userId!: string;
+
+ @ManyToOne(() => User, user => user.refreshTokens, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'userId' })
+ user!: User;
+
+ /** SHA-256 hash of the refresh token */
+ @Column({ length: 255 })
+ tokenHash!: string;
+
+ /** When this token expires */
+ @Column()
+ expiresAt!: Date;
+
+ /** Whether this token has been revoked */
+ @Column({ default: false })
+ isRevoked!: boolean;
+
+ /** Browser/device user agent string */
+ @Column({ length: 500, nullable: true })
+ userAgent?: string;
+
+ /** Client IP address (IPv6 compatible) */
+ @Column({ length: 45, nullable: true })
+ ipAddress?: string;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Check if token is valid (not revoked and not expired).
+ */
+ get isValid(): boolean {
+ return !this.isRevoked && new Date() < this.expiresAt;
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/seo-meta.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/seo-meta.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..2c3868bb6da75245a2a4c1face39feaa913e935f
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/seo-meta.entity.ts
@@ -0,0 +1,123 @@
+/**
+ * @fileoverview SeoMeta Entity - SEO metadata for pages
+ * @description Stores comprehensive SEO metadata including meta tags,
+ * Open Graph tags, Twitter Card data, and robots directives.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ OneToOne,
+ JoinColumn
+} from 'typeorm';
+import { Page } from './page.entity';
+
+/**
+ * SEO metadata entity for page-level SEO configuration
+ * @remarks
+ * - Meta tags (title, description, keywords)
+ * - Open Graph tags for social sharing
+ * - Twitter Card configuration
+ * - Canonical URL and robots directives
+ */
+@Entity('seo_meta')
+export class SeoMeta {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ /** Related page ID */
+ @Column('uuid')
+ pageId!: string;
+
+ // ============================================
+ // Basic Meta Tags
+ // ============================================
+
+ /** Meta title (overrides page title if set) */
+ @Column({ length: 255, nullable: true })
+ metaTitle?: string;
+
+ /** Meta description for search results */
+ @Column({ length: 500, nullable: true })
+ metaDescription?: string;
+
+ /** Meta keywords (comma-separated) */
+ @Column({ length: 500, nullable: true })
+ metaKeywords?: string;
+
+ /** Canonical URL (prevents duplicate content issues) */
+ @Column({ length: 500, nullable: true })
+ canonicalUrl?: string;
+
+ /** Prevent indexing by search engines */
+ @Column({ default: false })
+ noindex!: boolean;
+
+ /** Prevent following links on this page */
+ @Column({ default: false })
+ nofollow!: boolean;
+
+ // ============================================
+ // Open Graph (OG) Tags
+ // ============================================
+
+ /** OG title for social sharing */
+ @Column({ length: 255, nullable: true })
+ ogTitle?: string;
+
+ /** OG description for social sharing */
+ @Column({ length: 500, nullable: true })
+ ogDescription?: string;
+
+ /** OG image URL (absolute URL) */
+ @Column({ length: 500, nullable: true })
+ ogImage?: string;
+
+ /** OG type (website, article, profile, etc.) */
+ @Column({ length: 50, default: 'website' })
+ ogType!: string;
+
+ /** OG locale (e.g., en_US) */
+ @Column({ length: 10, nullable: true })
+ ogLocale?: string;
+
+ // ============================================
+ // Twitter Card Tags
+ // ============================================
+
+ /** Twitter card type (summary, summary_large_image, etc.) */
+ @Column({ length: 50, default: 'summary_large_image' })
+ twitterCard!: string;
+
+ /** Twitter title */
+ @Column({ length: 255, nullable: true })
+ twitterTitle?: string;
+
+ /** Twitter description */
+ @Column({ length: 500, nullable: true })
+ twitterDescription?: string;
+
+ /** Twitter image URL (absolute URL) */
+ @Column({ length: 500, nullable: true })
+ twitterImage?: string;
+
+ /** Twitter site handle (@username) */
+ @Column({ length: 50, nullable: true })
+ twitterSite?: string;
+
+ /** Twitter creator handle (@username) */
+ @Column({ length: 50, nullable: true })
+ twitterCreator?: string;
+
+ // ============================================
+ // Relations
+ // ============================================
+
+ /** Related page (1:1 inverse side) */
+ @OneToOne(() => Page, page => page.seoMeta, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'pageId' })
+ page!: Page;
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/site-settings.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/site-settings.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e005727885677c70825db7cf9e1cc226d729f743
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/site-settings.entity.ts
@@ -0,0 +1,181 @@
+/**
+ * @fileoverview SiteSettings Entity - Global site configuration
+ * @description Stores global site settings including company information,
+ * branding, social links, and default SEO metadata.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn
+} from 'typeorm';
+
+/**
+ * Site settings entity for global configuration
+ * @remarks
+ * - Singleton pattern (only one record should exist)
+ * - Company branding and information
+ * - Default SEO fallbacks
+ * - Social media links
+ * - Analytics configuration
+ */
+@Entity('site_settings')
+export class SiteSettings {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ // ============================================
+ // Site Identity
+ // ============================================
+
+ /** Site/company name */
+ @Column({ length: 255 })
+ siteName!: string;
+
+ /** Full site URL (e.g., https://example.com) */
+ @Column({ length: 255 })
+ siteUrl!: string;
+
+ /** Company/organization name */
+ @Column({ length: 255 })
+ companyName!: string;
+
+ /** Company logo URL (absolute URL) */
+ @Column({ length: 500, nullable: true })
+ logoUrl?: string;
+
+ /** Favicon URL */
+ @Column({ length: 500, nullable: true })
+ faviconUrl?: string;
+
+ // ============================================
+ // Default SEO Metadata
+ // ============================================
+
+ /** Default meta description (fallback) */
+ @Column({ length: 500, nullable: true })
+ defaultMetaDescription?: string;
+
+ /** Default OG image (fallback) */
+ @Column({ length: 500, nullable: true })
+ defaultOgImage?: string;
+
+ /** Default site keywords */
+ @Column({ length: 500, nullable: true })
+ defaultKeywords?: string;
+
+ // ============================================
+ // Social Media Links
+ // ============================================
+
+ /** Twitter/X profile URL */
+ @Column({ length: 255, nullable: true })
+ twitterUrl?: string;
+
+ /** LinkedIn profile/company URL */
+ @Column({ length: 255, nullable: true })
+ linkedinUrl?: string;
+
+ /** GitHub organization URL */
+ @Column({ length: 255, nullable: true })
+ githubUrl?: string;
+
+ /** Facebook page URL */
+ @Column({ length: 255, nullable: true })
+ facebookUrl?: string;
+
+ /** Instagram profile URL */
+ @Column({ length: 255, nullable: true })
+ instagramUrl?: string;
+
+ /** YouTube channel URL */
+ @Column({ length: 255, nullable: true })
+ youtubeUrl?: string;
+
+ /** Additional social links (JSON array of {name, url}) */
+ @Column('text', { nullable: true })
+ additionalSocialLinks?: string; // JSON array
+
+ // ============================================
+ // Contact Information
+ // ============================================
+
+ /** Primary contact email */
+ @Column({ length: 255, nullable: true })
+ contactEmail?: string;
+
+ /** Primary phone number */
+ @Column({ length: 50, nullable: true })
+ contactPhone?: string;
+
+ /** Physical address */
+ @Column('text', { nullable: true })
+ address?: string;
+
+ // ============================================
+ // Analytics & Verification
+ // ============================================
+
+ /** Google Analytics measurement ID (e.g., G-XXXXXXXXXX) */
+ @Column({ length: 50, nullable: true })
+ googleAnalyticsId?: string;
+
+ /** Google Search Console verification code */
+ @Column({ length: 255, nullable: true })
+ googleSiteVerification?: string;
+
+ /** Bing Webmaster Tools verification code */
+ @Column({ length: 255, nullable: true })
+ bingVerification?: string;
+
+ // ============================================
+ // Timestamps
+ // ============================================
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+
+ // ============================================
+ // Helper Methods
+ // ============================================
+
+ /**
+ * Get all social links as array
+ */
+ getAllSocialLinks(): Array<{ platform: string; url: string }> {
+ const links: Array<{ platform: string; url: string }> = [];
+
+ if (this.twitterUrl) links.push({ platform: 'Twitter', url: this.twitterUrl });
+ if (this.linkedinUrl) links.push({ platform: 'LinkedIn', url: this.linkedinUrl });
+ if (this.githubUrl) links.push({ platform: 'GitHub', url: this.githubUrl });
+ if (this.facebookUrl) links.push({ platform: 'Facebook', url: this.facebookUrl });
+ if (this.instagramUrl) links.push({ platform: 'Instagram', url: this.instagramUrl });
+ if (this.youtubeUrl) links.push({ platform: 'YouTube', url: this.youtubeUrl });
+
+ // Parse additional links
+ if (this.additionalSocialLinks) {
+ try {
+ const additional = JSON.parse(this.additionalSocialLinks);
+ links.push(...additional);
+ } catch {
+ // Invalid JSON, skip
+ }
+ }
+
+ return links;
+ }
+
+ /**
+ * Get social links formatted for Schema.org sameAs property
+ */
+ getSameAsLinks(): string[] {
+ return this.getAllSocialLinks().map(link => link.url);
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/skill-category.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/skill-category.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..03505f46e7140a1ddaea16e07d04b77db4409940
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/skill-category.entity.ts
@@ -0,0 +1,108 @@
+/**
+ * @fileoverview Skill Category Entity
+ * Organizes skills into named categories with visual customization.
+ *
+ * @module entities/skill-category
+ * @author Armand Richelet-Kleinberg
+ * @since 1.0.0
+ *
+ * @example
+ * // Creating a skill category
+ * const category = new SkillCategory();
+ * category.name = 'Frontend';
+ * category.description = 'UI development technologies';
+ * category.icon = 'Monitor';
+ * category.color = '#3B82F6';
+ * await repository.save(category);
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, OneToMany, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+import { Skill } from './skill.entity';
+
+/**
+ * Skill Category entity for organizing skills.
+ *
+ * @class SkillCategory
+ * @description Groups related skills together with visual customization options.
+ * Used in the CV/Resume section for organized skill presentation.
+ *
+ * @remarks
+ * - Categories can have custom colors and icons for visual distinction
+ * - displayOrder controls the rendering sequence
+ * - Skills are linked via foreign key relationship
+ *
+ * @see {@link Skill} for the related skill entity
+ */
+@Entity('skill_categories')
+export class SkillCategory {
+ /**
+ * Unique identifier for the category.
+ * @type {number}
+ */
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ /**
+ * Display name of the category.
+ * @type {string}
+ * @example 'Frontend', 'Backend', 'DevOps', 'Languages'
+ */
+ @Column({ length: 100 })
+ name!: string;
+
+ /**
+ * Optional description of the category.
+ * @type {string | null}
+ */
+ @Column({ length: 255, nullable: true })
+ description!: string;
+
+ /**
+ * Lucide icon name for visual representation.
+ * @type {string | null}
+ * @example 'Monitor', 'Server', 'Cloud', 'Code'
+ * @see https://lucide.dev/icons for available icons
+ */
+ @Column({ length: 50, nullable: true })
+ icon!: string;
+
+ /**
+ * Hex color code for category styling.
+ * @type {string | null}
+ * @example '#3B82F6', '#10B981', '#8B5CF6'
+ */
+ @Column({ length: 7, nullable: true })
+ color!: string;
+
+ /**
+ * Display order for sorting categories.
+ * @type {number}
+ * @default 0
+ * @remarks Lower values appear first
+ */
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /**
+ * Skills belonging to this category.
+ * @type {Skill[]}
+ * @remarks One-to-many relationship with Skill entity
+ */
+ @OneToMany(() => Skill, skill => skill.category)
+ skills!: Skill[];
+
+ /**
+ * Record creation timestamp.
+ * @type {Date}
+ */
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Record last update timestamp.
+ * @type {Date}
+ */
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/skill.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/skill.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..dc679f21df1938a40597ac9d042fcc56e0b1542b
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/skill.entity.ts
@@ -0,0 +1,61 @@
+/**
+ * @fileoverview Skill Entity
+ * Represents a skill in the CV with category support.
+ * Supports userId (new) and legacy profileId/collaboratorId.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn, Index } from 'typeorm';
+import { SkillCategory } from './skill-category.entity';
+import { User } from './user.entity';
+import { Collaborator } from './collaborator.entity';
+
+@Entity('skills')
+@Index('IDX_skills_userId', ['userId'])
+@Index('IDX_skills_displayOrder', ['displayOrder'])
+export class Skill {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({ length: 100 })
+ name!: string;
+
+ @Column({ length: 50, nullable: true })
+ level!: string;
+
+ @Column({ nullable: true })
+ categoryId!: number;
+
+ @ManyToOne(() => SkillCategory, category => category.skills, { nullable: true })
+ @JoinColumn({ name: 'categoryId' })
+ category!: SkillCategory;
+
+ @Column({ type: 'decimal', precision: 3, scale: 1, nullable: true })
+ yearsOfExperience!: number;
+
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /** @deprecated Use userId instead */
+ @Column({ default: 1 })
+ profileId!: number;
+
+ /** @deprecated Use userId instead - kept for migration */
+ @Column('uuid', { nullable: true })
+ collaboratorId?: string;
+
+ @ManyToOne(() => Collaborator, collaborator => collaborator.skills, { nullable: true })
+ @JoinColumn({ name: 'collaboratorId' })
+ collaborator?: Collaborator;
+
+ /** User who owns this skill (for personal resume) */
+ @Column('uuid', { nullable: true })
+ userId?: string;
+
+ @ManyToOne(() => User, user => user.skills, { nullable: true })
+ @JoinColumn({ name: 'userId' })
+ user?: User;
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/structured-data.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/structured-data.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..827867d2d3bd83ee314485cb488ef60a201270ac
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/structured-data.entity.ts
@@ -0,0 +1,102 @@
+/**
+ * @fileoverview StructuredData Entity - JSON-LD structured data storage
+ * @description Stores Schema.org structured data (JSON-LD) for enhanced
+ * search engine understanding and rich results in SERPs.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ ManyToOne,
+ JoinColumn,
+ Index
+} from 'typeorm';
+import { Page } from './page.entity';
+
+/**
+ * Common Schema.org types for type safety
+ */
+export enum SchemaType {
+ WEBSITE = 'WebSite',
+ ORGANIZATION = 'Organization',
+ WEBPAGE = 'WebPage',
+ ARTICLE = 'Article',
+ BLOG_POSTING = 'BlogPosting',
+ PERSON = 'Person',
+ FAQ_PAGE = 'FAQPage',
+ BREADCRUMB_LIST = 'BreadcrumbList',
+ CREATIVE_WORK = 'CreativeWork',
+ HOW_TO = 'HowTo',
+ ITEM_LIST = 'ItemList',
+ PRODUCT = 'Product',
+ CONTACT_PAGE = 'ContactPage',
+ ABOUT_PAGE = 'AboutPage'
+}
+
+/**
+ * Structured data entity for Schema.org JSON-LD storage
+ * @remarks
+ * - Flexible JSON storage for any Schema.org type
+ * - Multiple schemas per page supported
+ * - Active/inactive toggle for testing
+ */
+@Entity('structured_data')
+export class StructuredData {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ /** Related page ID */
+ @Column('uuid')
+ pageId!: string;
+
+ /** Schema.org type (e.g., Article, Organization, FAQPage) */
+ @Column({ length: 100 })
+ @Index('IDX_structured_data_type')
+ schemaType!: SchemaType | string;
+
+ /** JSON-LD schema data (flexible object storage) */
+ @Column('text')
+ schemaData!: string; // Stored as JSON string
+
+ /** Whether this schema is active (allows A/B testing) */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ /** Display order for multiple schemas on same page */
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ // ============================================
+ // Relations
+ // ============================================
+
+ /** Related page */
+ @ManyToOne(() => Page, page => page.structuredData, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'pageId' })
+ page!: Page;
+
+ // ============================================
+ // Helper Methods
+ // ============================================
+
+ /**
+ * Parse JSON schema data
+ */
+ getParsedSchema(): Record {
+ try {
+ return JSON.parse(this.schemaData);
+ } catch {
+ return {};
+ }
+ }
+
+ /**
+ * Set schema data from object
+ */
+ setSchemaData(data: Record): void {
+ this.schemaData = JSON.stringify(data);
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/style-config.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/style-config.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d65289247f3cfdc378c475e15e53b7b71b631274
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/style-config.entity.ts
@@ -0,0 +1,67 @@
+/**
+ * @fileoverview Style Config Entity
+ * Represents theme configuration settings in the database.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+import { ThemeColorSchemeEnum } from '@arkalliance/startupcms-ai-share';
+
+@Entity('style_config')
+export class StyleConfig {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column({ unique: true })
+ name!: string;
+
+ @Column({
+ type: 'simple-enum',
+ enum: ThemeColorSchemeEnum,
+ default: ThemeColorSchemeEnum.LIGHT
+ })
+ colorScheme!: ThemeColorSchemeEnum;
+
+ @Column({ default: '#ffffff' })
+ primaryColor!: string;
+
+ @Column({ default: '#000000' })
+ secondaryColor!: string;
+
+ @Column({ default: '#3b82f6' })
+ accentColor!: string;
+
+ @Column({ default: '#ffffff' })
+ backgroundColor!: string;
+
+ @Column({ default: '#1f2937' })
+ textColor!: string;
+
+ @Column('simple-json', { nullable: true })
+ colorPalette!: { name: string; value: string; description?: string }[];
+
+ @Column('simple-json', { nullable: true })
+ headingFont!: { family: string; fallback: string; weights: string[]; googleFontUrl?: string };
+
+ @Column('simple-json', { nullable: true })
+ bodyFont!: { family: string; fallback: string; weights: string[]; googleFontUrl?: string };
+
+ @Column({ default: 16 })
+ baseFontSize!: number;
+
+ @Column({ default: 4 })
+ borderRadius!: number;
+
+ @Column({ default: false })
+ isActive!: boolean;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/task.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/task.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f58cb763df932b206fa28fec08876fc9af16c97a
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/task.entity.ts
@@ -0,0 +1,176 @@
+/**
+ * @fileoverview Task Entity
+ * Represents a work item/accomplishment for a collaborator with recognition features.
+ *
+ * Design Philosophy:
+ * - Public visibility celebrates achievements and learned lessons (emulation)
+ * - Private visibility protects ongoing work (psychological safety)
+ * - Deadline metrics emphasize efficiency and growth, never punishment
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn,
+ ManyToOne,
+ JoinColumn,
+ Index
+} from 'typeorm';
+import { Collaborator } from './collaborator.entity';
+import { Project } from './project.entity';
+
+/**
+ * Task status values matching TaskStatus enum in Share layer.
+ */
+export type TaskStatusType = 'backlog' | 'ongoing' | 'achieved' | 'mistake';
+
+/**
+ * Task entity for tracking accomplishments and work items.
+ * Supports public recognition for achievements and lessons learned.
+ */
+@Entity('tasks')
+export class Task {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ // ============================================
+ // Core Information
+ // ============================================
+
+ /** Task title - short, descriptive */
+ @Column({ length: 200 })
+ title!: string;
+
+ /** Detailed description of the task/achievement */
+ @Column('text', { nullable: true })
+ description?: string;
+
+ /** Contributor's role in this task (e.g., "Lead Developer", "Architect") */
+ @Column({ length: 100, nullable: true })
+ role?: string;
+
+ /** Current workflow status */
+ @Index()
+ @Column({
+ type: 'varchar',
+ length: 20,
+ default: 'backlog'
+ })
+ status!: TaskStatusType;
+
+ // ============================================
+ // Deadline & Performance Metrics
+ // ============================================
+
+ /** Estimated effort in hours (set at task creation) */
+ @Column({ type: 'float', nullable: true })
+ estimatedDurationHours?: number;
+
+ /** Actual effort in hours (recorded at completion) */
+ @Column({ type: 'float', nullable: true })
+ actualDurationHours?: number;
+
+ /** Target completion date */
+ @Column({ type: 'date', nullable: true })
+ dueDate?: Date;
+
+ /** Actual completion date */
+ @Column({ type: 'date', nullable: true })
+ closingDate?: Date;
+
+ // ============================================
+ // Peer Evaluation (Recognition)
+ // ============================================
+
+ /** Average peer rating (1-5 stars) */
+ @Column({ type: 'float', default: 0 })
+ averageRating!: number;
+
+ /** Number of ratings received */
+ @Column({ type: 'int', default: 0 })
+ ratingCount!: number;
+
+ // ============================================
+ // Lesson Learned (Growth Mindset)
+ // ============================================
+
+ /** Whether a valuable lesson was extracted (makes mistakes visible publicly) */
+ @Column({ default: false })
+ lessonLearned!: boolean;
+
+ /** Title/summary of the lesson (safe for public display) */
+ @Column({ length: 200, nullable: true })
+ lessonTitle?: string;
+
+ /** Detailed lesson description (internal only) */
+ @Column('text', { nullable: true })
+ lessonDescription?: string;
+
+ // ============================================
+ // Display Order & Metadata
+ // ============================================
+
+ /** Priority/display order within collaborator's tasks */
+ @Column({ default: 0 })
+ displayOrder!: number;
+
+ /** Whether to highlight this task prominently */
+ @Column({ default: false })
+ isHighlighted!: boolean;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+
+ // ============================================
+ // Relations
+ // ============================================
+
+ /** Collaborator who owns/performed this task */
+ @Index()
+ @Column('uuid')
+ collaboratorId!: string;
+
+ @ManyToOne(() => Collaborator, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'collaboratorId' })
+ collaborator!: Collaborator;
+
+ /** Optional related project */
+ @Column('uuid', { nullable: true })
+ projectId?: string;
+
+ @ManyToOne(() => Project, { nullable: true, onDelete: 'SET NULL' })
+ @JoinColumn({ name: 'projectId' })
+ project?: Project;
+
+ // ============================================
+ // Computed Properties
+ // ============================================
+
+ /**
+ * Calculate deadline performance in hours.
+ * Positive = ahead of schedule, Negative = overrun.
+ */
+ get deadlinePerformanceHours(): number | null {
+ if (this.estimatedDurationHours != null && this.actualDurationHours != null) {
+ return this.estimatedDurationHours - this.actualDurationHours;
+ }
+ return null;
+ }
+
+ /**
+ * Check if this task qualifies for public visibility.
+ * Only Achieved tasks and Mistakes with lessons are public.
+ */
+ get isPubliclyVisible(): boolean {
+ if (this.status === 'achieved') return true;
+ if (this.status === 'mistake' && this.lessonLearned) return true;
+ return false;
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/team-member.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/team-member.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c98d24b893d09dc6ad4cb4e43146dda9f6466d41
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/team-member.entity.ts
@@ -0,0 +1,26 @@
+import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
+
+@Entity('team_members')
+export class TeamMember {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column()
+ name!: string;
+
+ @Column()
+ role!: string;
+
+ @Column({ nullable: true })
+ avatarUrl!: string;
+
+ @Column({ nullable: true })
+ bio!: string;
+
+ @Column({ nullable: true })
+ githubUrl!: string;
+
+ @Column({ nullable: true })
+ linkedinUrl!: string;
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/technology.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/technology.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..66d0e5dd1853b310e68001ce45bd50dee2236ab1
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/technology.entity.ts
@@ -0,0 +1,149 @@
+/**
+ * @fileoverview Technology Entity
+ * Represents a technology/framework used in portfolio projects.
+ *
+ * @module database/entities/technology.entity
+ * @author Armand Richelet-Kleinberg
+ *
+ * @description
+ * This entity stores master data for technologies, making them
+ * extensible via database without code changes. Each technology
+ * includes metadata like category, description, icon, and color
+ * for rich UI rendering.
+ *
+ * @example
+ * ```typescript
+ * const tech = new Technology();
+ * tech.key = 'react';
+ * tech.name = 'React';
+ * tech.label = 'React.js';
+ * tech.category = 'frontend';
+ * tech.description = 'A JavaScript library for building user interfaces';
+ * tech.icon = 'fab fa-react';
+ * tech.color = '#61DAFB';
+ * tech.website = 'https://react.dev';
+ * ```
+ */
+
+import { Entity, PrimaryColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';
+
+/**
+ * Technology category enumeration for filtering and grouping.
+ */
+export enum TechnologyCategory {
+ FRONTEND = 'frontend',
+ BACKEND = 'backend',
+ LANGUAGES = 'languages',
+ RUNTIMES = 'runtimes',
+ DATABASES = 'databases',
+ CLOUD = 'cloud',
+ DEVOPS = 'devops',
+ MESSAGING = 'messaging',
+ AI = 'ai',
+ ENTERPRISE = 'enterprise',
+ PATTERNS = 'patterns',
+ APIS = 'apis',
+ TESTING = 'testing',
+ MOBILE = 'mobile',
+ STYLING = 'styling'
+}
+
+/**
+ * Technology entity for storing technology/framework master data.
+ *
+ * @class Technology
+ * @description Stores technologies with rich metadata for display and categorization.
+ * Technologies are linked to projects via the ProjectTechnology junction entity.
+ */
+@Entity('technologies')
+export class Technology {
+ /**
+ * Unique key identifier (kebab-case, e.g., 'react', 'typescript', 'dotnet-8').
+ * Used as the primary key for stable references.
+ */
+ @PrimaryColumn({ length: 50 })
+ key!: string;
+
+ /**
+ * Display name (e.g., 'React', 'TypeScript', '.NET 8').
+ */
+ @Column({ length: 100 })
+ name!: string;
+
+ /**
+ * Extended label for display (e.g., 'React.js', 'Microsoft .NET 8').
+ * Falls back to name if not provided.
+ */
+ @Column({ length: 150, nullable: true })
+ label?: string;
+
+ /**
+ * Category for grouping (frontend, backend, databases, etc.).
+ */
+ @Column({ length: 50 })
+ category!: string;
+
+ /**
+ * Brief description of the technology.
+ */
+ @Column({ type: 'text', nullable: true })
+ description?: string;
+
+ /**
+ * Common abbreviation or acronym.
+ * @example 'PoW', 'ERC-20', 'ETH', 'SOL'
+ */
+ @Column({ length: 20, nullable: true })
+ abbreviation?: string;
+
+ /**
+ * Icon class (Font Awesome or Devicon).
+ * @example 'fab fa-react', 'devicon-typescript-plain'
+ */
+ @Column({ length: 100, nullable: true })
+ icon?: string;
+
+ /**
+ * Brand color in hex format.
+ * @example '#61DAFB'
+ */
+ @Column({ length: 20, nullable: true })
+ color?: string;
+
+ /**
+ * Official website URL.
+ */
+ @Column({ nullable: true })
+ website?: string;
+
+ /**
+ * Supported versions (optional, JSON array).
+ * @example ['16', '17', '18', '19']
+ */
+ @Column({ type: 'simple-array', nullable: true })
+ versions?: string[];
+
+ /**
+ * Display order within category.
+ */
+ @Column({ type: 'int', default: 0 })
+ order!: number;
+
+ /**
+ * Whether this technology is actively used/displayed.
+ */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ /**
+ * Creation timestamp.
+ */
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Last update timestamp.
+ */
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/theme.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/theme.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0505c40d2e646c4348373434e5c931bd84d24b54
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/theme.entity.ts
@@ -0,0 +1,111 @@
+/**
+ * @fileoverview Theme Entity
+ * Represents a visual theme stored in the database with full CSS content.
+ *
+ * @module database/entities/theme.entity
+ * @author Armand Richelet-Kleinberg
+ *
+ * @description
+ * This entity stores complete theme CSS content in the database,
+ * enabling dynamic theme loading and switching without redeployment.
+ * Each theme contains pre-compiled CSS that is injected at runtime.
+ *
+ * @example
+ * ```typescript
+ * const theme = new Theme();
+ * theme.name = 'Default Cyber';
+ * theme.slug = 'default-cyber';
+ * theme.cssContent = ':root { --neon-primary: #00d4ff; ... }';
+ * theme.isDefault = true;
+ * ```
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+
+/**
+ * Theme entity for storing visual themes with full CSS content.
+ *
+ * @class Theme
+ * @description Stores themes with complete CSS for dynamic runtime injection.
+ * Themes are loaded via API and injected into the document head.
+ */
+@Entity('themes')
+export class Theme {
+ /**
+ * Auto-generated primary key.
+ */
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ /**
+ * Human-readable theme name.
+ * @example 'Default Cyber', 'Neon Cyber', 'Minimal'
+ */
+ @Column({ length: 100 })
+ name!: string;
+
+ /**
+ * URL-safe unique identifier (kebab-case).
+ * @example 'default-cyber', 'neon-cyber', 'minimal'
+ */
+ @Column({ length: 100, unique: true })
+ slug!: string;
+
+ /**
+ * Brief description of the theme style.
+ */
+ @Column({ type: 'text', nullable: true })
+ description?: string;
+
+ /**
+ * Full CSS content for this theme.
+ * Contains CSS variables, utility classes, and component styles.
+ */
+ @Column({ type: 'text' })
+ cssContent!: string;
+
+ /**
+ * Preview color for theme selector (hex).
+ * @example '#00d4ff'
+ */
+ @Column({ length: 20, nullable: true })
+ previewColor?: string;
+
+ /**
+ * Icon or emoji for theme selector.
+ * @example '⚡', '✨', '○', '◇'
+ */
+ @Column({ length: 10, nullable: true })
+ icon?: string;
+
+ /**
+ * Whether this is the default theme.
+ * Only one theme should have this set to true.
+ */
+ @Column({ default: false })
+ isDefault!: boolean;
+
+ /**
+ * Display order in theme selector.
+ */
+ @Column({ type: 'int', default: 0 })
+ order!: number;
+
+ /**
+ * Whether this theme is active/visible.
+ */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ /**
+ * Creation timestamp.
+ */
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ /**
+ * Last update timestamp.
+ */
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/user-role.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/user-role.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8043626130ec87c3f5e202b72b2d51c7f30e452b
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/user-role.entity.ts
@@ -0,0 +1,60 @@
+/**
+ * @fileoverview User Role Entity
+ * Junction table for many-to-many relationship between User and Role.
+ * Enables multi-role support where users can have multiple roles simultaneously.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ ManyToOne,
+ JoinColumn,
+ Unique,
+ Index
+} from 'typeorm';
+import { User } from './user.entity';
+import { Role } from '@arkalliance/startupcms-ai-share';
+
+/**
+ * UserRole junction entity for multi-role support.
+ * @remarks
+ * - Each row represents one role assigned to one user
+ * - Unique constraint prevents duplicate role assignments
+ * - Tracks who assigned the role and when
+ */
+@Entity('user_roles')
+@Unique(['userId', 'role'])
+export class UserRole {
+ @PrimaryGeneratedColumn()
+ id!: number;
+
+ @Column('uuid')
+ userId!: string;
+
+ @ManyToOne(() => User, user => user.userRoles, { onDelete: 'CASCADE' })
+ @JoinColumn({ name: 'userId' })
+ user!: User;
+
+ /** Role enum value (stored as string for SQLite compatibility) */
+ @Index()
+ @Column({ type: 'varchar', length: 50 })
+ role!: Role;
+
+ /** When was this role assigned */
+ @CreateDateColumn()
+ assignedAt!: Date;
+
+ /** Who assigned this role (for audit trail) */
+ @Column('uuid', { nullable: true })
+ assignedById?: string;
+
+ @ManyToOne(() => User, { nullable: true, onDelete: 'SET NULL' })
+ @JoinColumn({ name: 'assignedById' })
+ assignedBy?: User;
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/user.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/user.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9b9100a7e081a2f799fa4ee77210f6452b749b14
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/user.entity.ts
@@ -0,0 +1,220 @@
+/**
+ * @fileoverview User Entity
+ * Extended to support multi-role RBAC, email confirmation, lockout,
+ * personal information, and resume data ownership.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import {
+ Entity,
+ PrimaryGeneratedColumn,
+ Column,
+ CreateDateColumn,
+ UpdateDateColumn,
+ OneToMany,
+ OneToOne
+} from 'typeorm';
+import { UserRole } from './user-role.entity';
+import { RefreshToken } from './refresh-token.entity';
+import { Experience } from './experience.entity';
+import { Education } from './education.entity';
+import { Skill } from './skill.entity';
+import { Language } from './language.entity';
+import { Hobby } from './hobby.entity';
+import { BusinessDomain } from './business-domain.entity';
+import { Role } from '@arkalliance/startupcms-ai-share';
+
+/**
+ * User entity for authentication and personal resume data.
+ * @remarks
+ * - Supports multi-role via UserRole junction table
+ * - Owns resume data (experiences, education, skills, etc.)
+ * - Can be optionally linked to Collaborator for team membership
+ */
+@Entity('users')
+export class User {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column({ unique: true })
+ username!: string;
+
+ @Column()
+ passwordHash!: string;
+
+ // ============================================
+ // Personal Information
+ // ============================================
+
+ /** User's first name */
+ @Column({ length: 100, nullable: true })
+ firstName?: string;
+
+ /** User's last name */
+ @Column({ length: 100, nullable: true })
+ lastName?: string;
+
+ /** User's email address */
+ @Column({ unique: true, nullable: true })
+ email?: string;
+
+ /** User avatar/photo URL */
+ @Column({ length: 500, nullable: true })
+ avatarUrl?: string;
+
+ /** Bio/overview text for resume */
+ @Column('text', { nullable: true })
+ bio?: string;
+
+ /** LinkedIn profile URL */
+ @Column({ length: 255, nullable: true })
+ linkedinUrl?: string;
+
+ /** GitHub profile URL */
+ @Column({ length: 255, nullable: true })
+ githubUrl?: string;
+
+ /** Twitter/X profile URL */
+ @Column({ length: 255, nullable: true })
+ twitterUrl?: string;
+
+ /** Job title for resume display */
+ @Column({ length: 200, nullable: true })
+ title?: string;
+
+ // ============================================
+ // Account Status
+ // ============================================
+
+ /**
+ * @deprecated Use userRoles relation instead.
+ * Kept for backward compatibility during migration.
+ */
+ @Column({ default: 'admin', name: 'role' })
+ roleLegacy!: string;
+
+ /** Whether user account is active */
+ @Column({ default: true })
+ isActive!: boolean;
+
+ /** Whether email has been confirmed */
+ @Column({ default: false })
+ emailConfirmed!: boolean;
+
+ /** Token for email confirmation */
+ @Column({ length: 255, nullable: true })
+ emailConfirmToken?: string;
+
+ /** When email confirmation token expires */
+ @Column({ nullable: true })
+ emailConfirmExpiry?: Date;
+
+ /** Token for password reset */
+ @Column({ length: 255, nullable: true })
+ passwordResetToken?: string;
+
+ /** When password reset token expires */
+ @Column({ nullable: true })
+ passwordResetExpiry?: Date;
+
+ /** Number of consecutive failed login attempts */
+ @Column({ default: 0 })
+ failedLoginAttempts!: number;
+
+ /** Account locked until this time */
+ @Column({ nullable: true })
+ lockoutUntil?: Date;
+
+ @Column({ nullable: true })
+ lastLogin?: Date;
+
+ /** Linked collaborator for team membership */
+ @Column('uuid', { nullable: true })
+ collaboratorId?: string;
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+
+ // ============================================
+ // Authentication Relations
+ // ============================================
+
+ @OneToMany(() => UserRole, userRole => userRole.user)
+ userRoles!: UserRole[];
+
+ @OneToMany(() => RefreshToken, token => token.user)
+ refreshTokens!: RefreshToken[];
+
+ // ============================================
+ // Resume Data Relations (Personal)
+ // ============================================
+
+ @OneToMany(() => Experience, experience => experience.user)
+ experiences!: Experience[];
+
+ @OneToMany(() => Education, education => education.user)
+ educations!: Education[];
+
+ @OneToMany(() => Skill, skill => skill.user)
+ skills!: Skill[];
+
+ @OneToMany(() => Language, language => language.user)
+ languages!: Language[];
+
+ @OneToMany(() => Hobby, hobby => hobby.user)
+ hobbies!: Hobby[];
+
+ @OneToMany(() => BusinessDomain, domain => domain.user)
+ businessDomains!: BusinessDomain[];
+
+ // ============================================
+ // Computed Properties
+ // ============================================
+
+ /** Full name for display */
+ get fullName(): string {
+ if (this.firstName && this.lastName) {
+ return `${this.firstName} ${this.lastName}`;
+ }
+ return this.username;
+ }
+
+ /**
+ * Get all role names for this user.
+ */
+ get roles(): Role[] {
+ if (!this.userRoles || this.userRoles.length === 0) {
+ // Fallback to legacy role if no UserRoles
+ return this.roleLegacy ? [this.roleLegacy as Role] : [];
+ }
+ return this.userRoles.map(ur => ur.role);
+ }
+
+ /**
+ * Check if user has a specific role.
+ */
+ hasRole(role: Role): boolean {
+ return this.roles.includes(role);
+ }
+
+ /**
+ * Check if user has any of the specified roles.
+ */
+ hasAnyRole(...roles: Role[]): boolean {
+ return roles.some(role => this.hasRole(role));
+ }
+
+ /**
+ * Check if account is currently locked.
+ */
+ get isLocked(): boolean {
+ return this.lockoutUntil != null && new Date() < this.lockoutUntil;
+ }
+}
+
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/widget.entity.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/widget.entity.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f0fe0f40d70aba486020771348d0466e789b551d
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/entities/widget.entity.ts
@@ -0,0 +1,43 @@
+/**
+ * @fileoverview Widget Entity
+ * Database entity for dynamic widgets on portfolio pages.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
+import { WidgetTypeEnum } from '@arkalliance/startupcms-ai-share';
+
+@Entity('widgets')
+export class Widget {
+ @PrimaryGeneratedColumn('uuid')
+ id!: string;
+
+ @Column({
+ type: 'text', // using text for sqlite compatibility
+ default: WidgetTypeEnum.TEXT
+ })
+ type!: WidgetTypeEnum;
+
+ @Column()
+ title!: string;
+
+ @Column({ default: 0 })
+ order!: number;
+
+ @Column('simple-json', { nullable: true })
+ config!: Record; // Flexible JSON storage for specific widget settings
+
+ @Column({ nullable: true })
+ context!: string; // e.g., 'HOME', 'PROJECT_123'
+
+ @CreateDateColumn()
+ createdAt!: Date;
+
+ @UpdateDateColumn()
+ updatedAt!: Date;
+}
+
+
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/ai-settings.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/ai-settings.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..fe61e0befb88011097e6a8bf02c6f8f15b158ba1
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/ai-settings.repository.ts
@@ -0,0 +1,22 @@
+/**
+ * @fileoverview AI Settings Repository
+ * Repository for AI configuration management.
+ */
+
+import { GenericRepository } from './generic.repository';
+import { AiSettings } from '../entities/ai-settings.entity';
+
+export class AiSettingsRepository extends GenericRepository {
+ constructor() {
+ super(AiSettings);
+ }
+
+ async getActive(): Promise {
+ return this.repository.findOne({ where: { isActive: true } });
+ }
+
+ async getFirst(): Promise {
+ return this.repository.findOne({ where: {} });
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/audit-log.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/audit-log.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..70d67ee662b67f5bae4189c91ce109ed3a5a7b87
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/audit-log.repository.ts
@@ -0,0 +1,147 @@
+/**
+ * @fileoverview Audit Log Repository
+ * Data access layer for AuditLog entity with query support.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Repository, DataSource, Between, Like, In } from 'typeorm';
+import { AuditLog } from '../entities/audit-log.entity';
+import { AuditAction } from '@arkalliance/startupcms-ai-share';
+import { AppDataSource } from '../../config/database';
+
+/**
+ * Query options for audit log search.
+ */
+export interface AuditLogQueryOptions {
+ userId?: string;
+ actions?: AuditAction[];
+ startDate?: Date;
+ endDate?: Date;
+ success?: boolean;
+ ipAddress?: string;
+ page?: number;
+ limit?: number;
+}
+
+/**
+ * Repository for AuditLog entity operations.
+ */
+export class AuditLogRepository {
+ private repository: Repository;
+
+ constructor(dataSource?: DataSource) {
+ this.repository = (dataSource || AppDataSource).getRepository(AuditLog);
+ }
+
+ /**
+ * Create a new audit log entry.
+ */
+ async log(entry: {
+ userId?: string;
+ action: AuditAction;
+ ipAddress?: string;
+ userAgent?: string;
+ success?: boolean;
+ details?: Record;
+ }): Promise {
+ const auditLog = this.repository.create({
+ ...entry,
+ success: entry.success ?? true,
+ details: entry.details ? JSON.stringify(entry.details) : undefined
+ });
+ return this.repository.save(auditLog);
+ }
+
+ /**
+ * Query audit logs with filters.
+ */
+ async query(options: AuditLogQueryOptions): Promise<{ logs: AuditLog[]; total: number }> {
+ const {
+ userId,
+ actions,
+ startDate,
+ endDate,
+ success,
+ ipAddress,
+ page = 1,
+ limit = 50
+ } = options;
+
+ const queryBuilder = this.repository.createQueryBuilder('log')
+ .leftJoinAndSelect('log.user', 'user')
+ .orderBy('log.createdAt', 'DESC');
+
+ if (userId) {
+ queryBuilder.andWhere('log.userId = :userId', { userId });
+ }
+
+ if (actions && actions.length > 0) {
+ queryBuilder.andWhere('log.action IN (:...actions)', { actions });
+ }
+
+ if (startDate && endDate) {
+ queryBuilder.andWhere('log.createdAt BETWEEN :startDate AND :endDate', {
+ startDate,
+ endDate
+ });
+ } else if (startDate) {
+ queryBuilder.andWhere('log.createdAt >= :startDate', { startDate });
+ } else if (endDate) {
+ queryBuilder.andWhere('log.createdAt <= :endDate', { endDate });
+ }
+
+ if (success !== undefined) {
+ queryBuilder.andWhere('log.success = :success', { success });
+ }
+
+ if (ipAddress) {
+ queryBuilder.andWhere('log.ipAddress LIKE :ipAddress', { ipAddress: `%${ipAddress}%` });
+ }
+
+ const total = await queryBuilder.getCount();
+ const logs = await queryBuilder
+ .skip((page - 1) * limit)
+ .take(limit)
+ .getMany();
+
+ return { logs, total };
+ }
+
+ /**
+ * Get recent login attempts for a user.
+ */
+ async getRecentLoginAttempts(userId: string, limit = 10): Promise {
+ return this.repository.find({
+ where: {
+ userId,
+ action: In([AuditAction.LOGIN_SUCCESS, AuditAction.LOGIN_FAILURE])
+ },
+ order: { createdAt: 'DESC' },
+ take: limit
+ });
+ }
+
+ /**
+ * Get failed login count in last X minutes.
+ */
+ async getRecentFailedLoginCount(userId: string, minutes: number): Promise {
+ const since = new Date(Date.now() - minutes * 60 * 1000);
+ return this.repository.count({
+ where: {
+ userId,
+ action: AuditAction.LOGIN_FAILURE,
+ createdAt: Between(since, new Date())
+ }
+ });
+ }
+
+ /**
+ * Count total events.
+ */
+ async countAll(): Promise {
+ return this.repository.count();
+ }
+}
+
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/carousel.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/carousel.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..bab475afd9a2abe65001790825ec800899699074
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/carousel.repository.ts
@@ -0,0 +1,42 @@
+/**
+ * @fileoverview Carousel Repository
+ * Data access layer for carousel item entities.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { GenericRepository } from './generic.repository';
+import { CarouselItem } from '../entities/carousel-item.entity';
+
+export class CarouselRepository extends GenericRepository {
+ constructor() {
+ super(CarouselItem);
+ }
+
+ /**
+ * Get all carousel items ordered by display order.
+ */
+ async findAllOrdered(): Promise {
+ return this.repository.find({ order: { order: 'ASC' } });
+ }
+
+ /**
+ * Get only active carousel items.
+ */
+ async findActive(): Promise {
+ return this.repository.find({
+ where: { isActive: true },
+ order: { order: 'ASC' }
+ });
+ }
+
+ /**
+ * Update order of carousel items.
+ */
+ async updateOrder(itemIds: number[]): Promise {
+ for (let i = 0; i < itemIds.length; i++) {
+ await this.repository.update(itemIds[i], { order: i });
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/collaborator.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/collaborator.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1b83e0c0e774d230b51350e4c0de9773152a7793
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/collaborator.repository.ts
@@ -0,0 +1,106 @@
+/**
+ * @fileoverview Collaborator Repository
+ * Data access layer for Collaborator entity with hierarchy support.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { Repository, DataSource, IsNull } from 'typeorm';
+import { Collaborator } from '../entities/collaborator.entity';
+import { AppDataSource } from '../../config/database';
+
+/**
+ * Repository for Collaborator entity operations.
+ */
+export class CollaboratorRepository {
+ private repository: Repository;
+
+ constructor(dataSource?: DataSource) {
+ this.repository = (dataSource || AppDataSource).getRepository(Collaborator);
+ }
+
+ /**
+ * Find collaborator by ID.
+ */
+ async findById(id: string): Promise {
+ return this.repository.findOne({
+ where: { id },
+ relations: ['organization', 'reportsTo', 'directReports']
+ });
+ }
+
+ /**
+ * Find collaborator by user ID.
+ */
+ async findByUserId(userId: string): Promise {
+ return this.repository.findOne({
+ where: { userId },
+ relations: ['organization']
+ });
+ }
+
+ /**
+ * Get all collaborators for an organization.
+ */
+ async findByOrganization(organizationId: string): Promise {
+ return this.repository.find({
+ where: { organizationId, isActive: true },
+ relations: ['reportsTo'],
+ order: { displayOrder: 'ASC', firstName: 'ASC' }
+ });
+ }
+
+ /**
+ * Get top-level collaborators (no manager).
+ */
+ async findRootCollaborators(organizationId: string): Promise {
+ return this.repository.find({
+ where: { organizationId, reportsToId: IsNull(), isActive: true },
+ relations: ['directReports'],
+ order: { displayOrder: 'ASC' }
+ });
+ }
+
+ /**
+ * Get direct reports for a collaborator.
+ */
+ async findDirectReports(collaboratorId: string): Promise {
+ return this.repository.find({
+ where: { reportsToId: collaboratorId, isActive: true },
+ order: { displayOrder: 'ASC', firstName: 'ASC' }
+ });
+ }
+
+ /**
+ * Create new collaborator.
+ */
+ async create(data: Partial): Promise {
+ const collaborator = this.repository.create(data);
+ return this.repository.save(collaborator);
+ }
+
+ /**
+ * Update collaborator.
+ */
+ async update(id: string, data: Partial): Promise {
+ await this.repository.update(id, data);
+ return this.findById(id);
+ }
+
+ /**
+ * Update hierarchy (change manager).
+ */
+ async updateReportsTo(id: string, reportsToId: string | null): Promise {
+ const result = await this.repository.update(id, { reportsToId: reportsToId || undefined });
+ return (result.affected ?? 0) > 0;
+ }
+
+ /**
+ * Count collaborators in organization.
+ */
+ async countByOrganization(organizationId: string): Promise {
+ return this.repository.count({
+ where: { organizationId, isActive: true }
+ });
+ }
+}
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/education.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/education.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..33815182c8774117a51664de1d6a37af35cb840e
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/education.repository.ts
@@ -0,0 +1,20 @@
+/**
+ * @fileoverview Education Repository
+ * Repository for education management.
+ */
+
+import { GenericRepository } from './generic.repository';
+import { Education } from '../entities/education.entity';
+
+export class EducationRepository extends GenericRepository {
+ constructor() {
+ super(Education);
+ }
+
+ async findAllOrdered(): Promise {
+ return this.repository.find({
+ order: { startDate: 'DESC' }
+ });
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/experience.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/experience.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..39ee9e6989753039aa1a8eac1576f03b533ded39
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/experience.repository.ts
@@ -0,0 +1,33 @@
+/**
+ * @fileoverview Experience Repository
+ * Repository for experience management.
+ */
+
+import { GenericRepository } from './generic.repository';
+import { Experience } from '../entities/experience.entity';
+
+export class ExperienceRepository extends GenericRepository {
+ constructor() {
+ super(Experience);
+ }
+
+ async findAllOrdered(): Promise {
+ return this.repository.find({
+ order: { displayOrder: 'ASC', startDate: 'DESC' }
+ });
+ }
+
+ async findHighlighted(): Promise {
+ return this.repository.find({
+ where: { isHighlighted: true },
+ order: { startDate: 'DESC' }
+ });
+ }
+
+ async updateOrder(experienceIds: number[]): Promise {
+ for (let i = 0; i < experienceIds.length; i++) {
+ await this.repository.update(experienceIds[i], { displayOrder: i });
+ }
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/generic.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/generic.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..f4849c9f110ccd03f631b3caf7623a76259480d5
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/generic.repository.ts
@@ -0,0 +1,35 @@
+import { Repository, DeepPartial, FindOptionsWhere, FindOneOptions } from 'typeorm';
+import { AppDataSource } from '../../config/database';
+
+export class GenericRepository {
+ protected repository: Repository;
+
+ constructor(entity: any) {
+ this.repository = AppDataSource.getRepository(entity);
+ }
+
+ async findAll(options?: any): Promise {
+ return this.repository.find(options);
+ }
+
+ async findById(id: any, options?: FindOneOptions): Promise {
+ // @ts-ignore - TypeORM generic handling
+ return this.repository.findOne({ where: { id }, ...options });
+ }
+
+ async create(data: DeepPartial): Promise {
+ const entity = this.repository.create(data);
+ return this.repository.save(entity);
+ }
+
+ async update(id: any, data: DeepPartial): Promise {
+ // @ts-ignore
+ await this.repository.update(id, data);
+ return this.findById(id);
+ }
+
+ async delete(id: any): Promise {
+ await this.repository.delete(id);
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/media.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/media.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..c6c47829252554f354c3db8ea4ff2b99bb29922e
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/media.repository.ts
@@ -0,0 +1,33 @@
+/**
+ * @fileoverview Media Repository
+ * Data access layer for media asset entities.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { GenericRepository } from './generic.repository';
+import { Media } from '../entities/media.entity';
+
+export class MediaRepository extends GenericRepository {
+ constructor() {
+ super(Media);
+ }
+
+ /**
+ * Get media by type filter.
+ */
+ async findByType(type: string): Promise {
+ return this.repository.find({
+ where: { type: type as any },
+ order: { createdAt: 'DESC' }
+ });
+ }
+
+ /**
+ * Get all media ordered by creation date.
+ */
+ async findAllOrdered(): Promise {
+ return this.repository.find({ order: { createdAt: 'DESC' } });
+ }
+}
+
diff --git a/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/menu.repository.ts b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/menu.repository.ts
new file mode 100644
index 0000000000000000000000000000000000000000..22e3bad32001d4eb56a617dba0ebe862d7152f96
--- /dev/null
+++ b/Ark.Alliance.StartupCms.Ai.Backend/src/database/repositories/menu.repository.ts
@@ -0,0 +1,45 @@
+/**
+ * @fileoverview Menu Repository
+ * Data access layer for menu item entities.
+ *
+ * @author Armand Richelet-Kleinberg
+ */
+
+import { GenericRepository } from './generic.repository';
+import { MenuItem } from '../entities/menu-item.entity';
+import { MenuPositionEnum } from '@arkalliance/startupcms-ai-share';
+
+export class MenuRepository extends GenericRepository