@gravito/zenith 1.1.2 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -22
- package/README.zh-TW.md +88 -0
- package/dist/bin.js +54699 -39316
- package/dist/client/assets/index-C80c1frR.css +1 -0
- package/dist/client/assets/index-CrWem9u3.js +434 -0
- package/dist/client/index.html +2 -2
- package/dist/server/index.js +54699 -39316
- package/package.json +20 -9
- package/CHANGELOG.md +0 -47
- package/Dockerfile +0 -46
- package/Dockerfile.demo-worker +0 -29
- package/ECOSYSTEM_EXPANSION_RFC.md +0 -130
- package/bin/flux-console.ts +0 -2
- package/dist/client/assets/index-BSMp8oq_.js +0 -436
- package/dist/client/assets/index-BwxlHx-_.css +0 -1
- package/docker-compose.yml +0 -40
- package/docs/ALERTING_GUIDE.md +0 -71
- package/docs/DEPLOYMENT.md +0 -157
- package/docs/DOCS_INTERNAL.md +0 -73
- package/docs/LARAVEL_ZENITH_ROADMAP.md +0 -109
- package/docs/QUASAR_MASTER_PLAN.md +0 -140
- package/docs/QUICK_TEST_GUIDE.md +0 -72
- package/docs/ROADMAP.md +0 -85
- package/docs/integrations/LARAVEL.md +0 -207
- package/postcss.config.js +0 -6
- package/scripts/debug_redis_keys.ts +0 -24
- package/scripts/flood-logs.ts +0 -21
- package/scripts/seed.ts +0 -213
- package/scripts/verify-throttle.ts +0 -49
- package/scripts/worker.ts +0 -124
- package/specs/PULSE_SPEC.md +0 -86
- package/src/bin.ts +0 -6
- package/src/client/App.tsx +0 -72
- package/src/client/Layout.tsx +0 -672
- package/src/client/Sidebar.tsx +0 -112
- package/src/client/ThroughputChart.tsx +0 -144
- package/src/client/WorkerStatus.tsx +0 -226
- package/src/client/components/BrandIcons.tsx +0 -168
- package/src/client/components/ConfirmDialog.tsx +0 -126
- package/src/client/components/JobInspector.tsx +0 -554
- package/src/client/components/LogArchiveModal.tsx +0 -432
- package/src/client/components/NotificationBell.tsx +0 -212
- package/src/client/components/PageHeader.tsx +0 -47
- package/src/client/components/Toaster.tsx +0 -90
- package/src/client/components/UserProfileDropdown.tsx +0 -186
- package/src/client/contexts/AuthContext.tsx +0 -105
- package/src/client/contexts/NotificationContext.tsx +0 -128
- package/src/client/index.css +0 -174
- package/src/client/index.html +0 -12
- package/src/client/main.tsx +0 -15
- package/src/client/pages/LoginPage.tsx +0 -162
- package/src/client/pages/MetricsPage.tsx +0 -417
- package/src/client/pages/OverviewPage.tsx +0 -517
- package/src/client/pages/PulsePage.tsx +0 -488
- package/src/client/pages/QueuesPage.tsx +0 -379
- package/src/client/pages/SchedulesPage.tsx +0 -540
- package/src/client/pages/SettingsPage.tsx +0 -1020
- package/src/client/pages/WorkersPage.tsx +0 -394
- package/src/client/pages/index.ts +0 -8
- package/src/client/utils.ts +0 -15
- package/src/server/config/ServerConfigManager.ts +0 -90
- package/src/server/index.ts +0 -860
- package/src/server/middleware/auth.ts +0 -127
- package/src/server/services/AlertService.ts +0 -321
- package/src/server/services/CommandService.ts +0 -137
- package/src/server/services/LogStreamProcessor.ts +0 -93
- package/src/server/services/MaintenanceScheduler.ts +0 -78
- package/src/server/services/PulseService.ts +0 -91
- package/src/server/services/QueueMetricsCollector.ts +0 -138
- package/src/server/services/QueueService.ts +0 -631
- package/src/shared/types.ts +0 -198
- package/tailwind.config.js +0 -73
- package/tests/placeholder.test.ts +0 -7
- package/tsconfig.json +0 -38
- package/tsconfig.node.json +0 -12
- package/vite.config.ts +0 -27
|
@@ -1 +0,0 @@
|
|
|
1
|
-
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--background: 0 0% 100%;--foreground: 224 71.4% 4.1%;--card: 0 0% 100%;--card-foreground: 224 71.4% 4.1%;--popover: 0 0% 100%;--popover-foreground: 224 71.4% 4.1%;--primary: 238.7 83.5% 66.7%;--primary-foreground: 210 20% 98%;--secondary: 220 14.3% 95.9%;--secondary-foreground: 238.7 83.5% 66.7%;--muted: 220 14.3% 95.9%;--muted-foreground: 220 8.9% 46.1%;--accent: 220 14.3% 95.9%;--accent-foreground: 238.7 83.5% 66.7%;--destructive: 0 84.2% 60.2%;--destructive-foreground: 210 20% 98%;--border: 220 13% 91%;--input: 220 13% 91%;--ring: 238.7 83.5% 66.7%;--radius: 1rem}.dark{--background: 222 47% 2%;--foreground: 213 31% 91%;--card: 222 47% 6%;--card-foreground: 213 31% 91%;--popover: 222 47% 4%;--popover-foreground: 213 31% 91%;--primary: 238.7 83.5% 66.7%;--primary-foreground: 222 47% 4%;--secondary: 222 47% 10%;--secondary-foreground: 213 31% 91%;--muted: 222 47% 8%;--muted-foreground: 215.4 16.3% 56.9%;--accent: 222 47% 12%;--accent-foreground: 213 31% 91%;--destructive: 0 62.8% 30.6%;--destructive-foreground: 210 20% 98%;--border: 222 47% 14%;--input: 222 47% 12%;--ring: 238.7 83.5% 66.7%}*{border-color:hsl(var(--border))}body{background-color:hsl(var(--background));color:hsl(var(--foreground));-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-feature-settings:"ss01","ss02","cv01","cv02","cv03"}.dark body{background-image:radial-gradient(at 50% 0%,hsla(238,83%,66%,.05) 0%,transparent 50%),radial-gradient(at 100% 100%,hsla(238,83%,66%,.02) 0%,transparent 50%);background-attachment:fixed}.container{width:100%}@media(min-width:640px){.container{max-width:640px}}@media(min-width:768px){.container{max-width:768px}}@media(min-width:1024px){.container{max-width:1024px}}@media(min-width:1280px){.container{max-width:1280px}}@media(min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.visible{visibility:visible}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.-bottom-1{bottom:-.25rem}.-left-1\/4{left:-25%}.-right-1{right:-.25rem}.-right-1\/4{right:-25%}.bottom-0{bottom:0}.bottom-1\/4{bottom:25%}.bottom-8{bottom:2rem}.bottom-full{bottom:100%}.left-0{left:0}.left-1{left:.25rem}.left-1\/2{left:50%}.left-3{left:.75rem}.left-4{left:1rem}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-4{right:1rem}.right-8{right:2rem}.top-0{top:0}.top-1\.5{top:.375rem}.top-1\/2{top:50%}.top-1\/4{top:25%}.top-4{top:1rem}.top-full{top:100%}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[1001\]{z-index:1001}.z-\[1002\]{z-index:1002}.z-\[100\]{z-index:100}.z-\[2000\]{z-index:2000}.z-\[4000\]{z-index:4000}.z-\[5000\]{z-index:5000}.col-span-2{grid-column:span 2 / span 2}.col-span-full{grid-column:1 / -1}.-mx-2{margin-left:-.5rem;margin-right:-.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-auto{margin-left:auto}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.h-1{height:.25rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-12{height:3rem}.h-14{height:3.5rem}.h-16{height:4rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-32{height:8rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-64{height:16rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-96{height:24rem}.h-\[300px\]{height:300px}.h-\[350px\]{height:350px}.h-\[400px\]{height:400px}.h-\[85vh\]{height:85vh}.h-full{height:100%}.h-screen{height:100vh}.max-h-\[400px\]{max-height:400px}.max-h-\[850px\]{max-height:850px}.min-h-0{min-height:0px}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-1\.5{width:.375rem}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-16{width:4rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-20{width:5rem}.w-24{width:6rem}.w-3{width:.75rem}.w-32{width:8rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-72{width:18rem}.w-8{width:2rem}.w-96{width:24rem}.w-\[1px\]{width:1px}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[140px\]{min-width:140px}.min-w-\[16px\]{min-width:16px}.min-w-\[200px\]{min-width:200px}.max-w-2xl{max-width:42rem}.max-w-4xl{max-width:56rem}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.flex-1{flex:1 1 0%}.flex-none{flex:none}.flex-shrink-0,.shrink-0{flex-shrink:0}.origin-left{transform-origin:left}.-translate-x-1{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-1\/2{--tw-translate-x: 50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-\[1\.02\]{--tw-scale-x: 1.02;--tw-scale-y: 1.02;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes ping{75%,to{transform:scale(2);opacity:0}}.animate-ping{animation:ping 1s cubic-bezier(0,0,.2,1) infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-12>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(3rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(3rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border\/10>:not([hidden])~:not([hidden]){border-color:hsl(var(--border) / .1)}.divide-border\/30>:not([hidden])~:not([hidden]){border-color:hsl(var(--border) / .3)}.divide-border\/50>:not([hidden])~:not([hidden]){border-color:hsl(var(--border) / .5)}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.scroll-smooth{scroll-behavior:smooth}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-r-full{border-top-right-radius:9999px;border-bottom-right-radius:9999px}.rounded-t-lg{border-top-left-radius:var(--radius);border-top-right-radius:var(--radius)}.rounded-bl-full{border-bottom-left-radius:9999px}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-none{border-style:none}.border-amber-500{--tw-border-opacity: 1;border-color:rgb(245 158 11 / var(--tw-border-opacity, 1))}.border-amber-500\/10{border-color:#f59e0b1a}.border-amber-500\/20{border-color:#f59e0b33}.border-amber-500\/30{border-color:#f59e0b4d}.border-background{border-color:hsl(var(--background))}.border-blue-500{--tw-border-opacity: 1;border-color:rgb(59 130 246 / var(--tw-border-opacity, 1))}.border-border{border-color:hsl(var(--border))}.border-border\/10{border-color:hsl(var(--border) / .1)}.border-border\/20{border-color:hsl(var(--border) / .2)}.border-border\/30{border-color:hsl(var(--border) / .3)}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/5{border-color:hsl(var(--border) / .05)}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-card{border-color:hsl(var(--card))}.border-green-500{--tw-border-opacity: 1;border-color:rgb(34 197 94 / var(--tw-border-opacity, 1))}.border-green-500\/20{border-color:#22c55e33}.border-indigo-500{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity, 1))}.border-primary{border-color:hsl(var(--primary))}.border-primary-foreground\/30{border-color:hsl(var(--primary-foreground) / .3)}.border-primary\/10{border-color:hsl(var(--primary) / .1)}.border-primary\/20{border-color:hsl(var(--primary) / .2)}.border-primary\/50{border-color:hsl(var(--primary) / .5)}.border-red-500{--tw-border-opacity: 1;border-color:rgb(239 68 68 / var(--tw-border-opacity, 1))}.border-red-500\/10{border-color:#ef44441a}.border-red-500\/20{border-color:#ef444433}.border-red-600{--tw-border-opacity: 1;border-color:rgb(220 38 38 / var(--tw-border-opacity, 1))}.border-transparent{border-color:transparent}.border-yellow-500\/20{border-color:#eab30833}.border-t-primary-foreground{border-top-color:hsl(var(--primary-foreground))}.bg-\[\#4A154B\]\/10{background-color:#4a154b1a}.bg-\[\#5865F2\]\/10{background-color:#5865f21a}.bg-amber-500{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.bg-amber-500\/10{background-color:#f59e0b1a}.bg-amber-500\/20{background-color:#f59e0b33}.bg-amber-500\/5{background-color:#f59e0b0d}.bg-background{background-color:hsl(var(--background))}.bg-background\/50{background-color:hsl(var(--background) / .5)}.bg-background\/80{background-color:hsl(var(--background) / .8)}.bg-black\/20{background-color:#0003}.bg-black\/60{background-color:#0009}.bg-blue-500{--tw-bg-opacity: 1;background-color:rgb(59 130 246 / var(--tw-bg-opacity, 1))}.bg-blue-500\/10{background-color:#3b82f61a}.bg-blue-500\/20{background-color:#3b82f633}.bg-border\/30{background-color:hsl(var(--border) / .3)}.bg-border\/50{background-color:hsl(var(--border) / .5)}.bg-card{background-color:hsl(var(--card))}.bg-card\/50{background-color:hsl(var(--card) / .5)}.bg-card\/80{background-color:hsl(var(--card) / .8)}.bg-current{background-color:currentColor}.bg-emerald-500{--tw-bg-opacity: 1;background-color:rgb(16 185 129 / var(--tw-bg-opacity, 1))}.bg-foreground{background-color:hsl(var(--foreground))}.bg-green-500{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity, 1))}.bg-green-500\/10{background-color:#22c55e1a}.bg-green-500\/20{background-color:#22c55e33}.bg-green-500\/40{background-color:#22c55e66}.bg-indigo-500{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity, 1))}.bg-indigo-500\/10{background-color:#6366f11a}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground{background-color:hsl(var(--muted-foreground))}.bg-muted-foreground\/20{background-color:hsl(var(--muted-foreground) / .2)}.bg-muted-foreground\/30{background-color:hsl(var(--muted-foreground) / .3)}.bg-muted-foreground\/40{background-color:hsl(var(--muted-foreground) / .4)}.bg-muted\/10{background-color:hsl(var(--muted) / .1)}.bg-muted\/20{background-color:hsl(var(--muted) / .2)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/40{background-color:hsl(var(--muted) / .4)}.bg-muted\/5{background-color:hsl(var(--muted) / .05)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-orange-500{--tw-bg-opacity: 1;background-color:rgb(249 115 22 / var(--tw-bg-opacity, 1))}.bg-orange-500\/10{background-color:#f973161a}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary-foreground{background-color:hsl(var(--primary-foreground))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/40{background-color:hsl(var(--primary) / .4)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.bg-red-500\/10{background-color:#ef44441a}.bg-red-500\/20{background-color:#ef444433}.bg-red-500\/5{background-color:#ef44440d}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/10{background-color:#ffffff1a}.bg-white\/20{background-color:#fff3}.bg-yellow-500{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity, 1))}.bg-yellow-500\/10{background-color:#eab3081a}.bg-\[linear-gradient\(rgba\(var\(--primary-rgb\)\,0\.03\)_1px\,transparent_1px\)\,linear-gradient\(90deg\,rgba\(var\(--primary-rgb\)\,0\.03\)_1px\,transparent_1px\)\]{background-image:linear-gradient(rgba(var(--primary-rgb),.03) 1px,transparent 1px),linear-gradient(90deg,rgba(var(--primary-rgb),.03) 1px,transparent 1px)}.bg-gradient-to-bl{background-image:linear-gradient(to bottom left,var(--tw-gradient-stops))}.bg-gradient-to-br{background-image:linear-gradient(to bottom right,var(--tw-gradient-stops))}.bg-gradient-to-l{background-image:linear-gradient(to left,var(--tw-gradient-stops))}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-card{--tw-gradient-from: hsl(var(--card)) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--card) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-emerald-500{--tw-gradient-from: #10b981 var(--tw-gradient-from-position);--tw-gradient-to: rgb(16 185 129 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary{--tw-gradient-from: hsl(var(--primary)) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary\/10{--tw-gradient-from: hsl(var(--primary) / .1) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-primary\/5{--tw-gradient-from: hsl(var(--primary) / .05) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-red-500{--tw-gradient-from: #ef4444 var(--tw-gradient-from-position);--tw-gradient-to: rgb(239 68 68 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.from-yellow-500{--tw-gradient-from: #eab308 var(--tw-gradient-from-position);--tw-gradient-to: rgb(234 179 8 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-card{--tw-gradient-to: hsl(var(--card) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), hsl(var(--card)) var(--tw-gradient-via-position), var(--tw-gradient-to)}.via-transparent{--tw-gradient-to: rgb(0 0 0 / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), transparent var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-indigo-500\/10{--tw-gradient-to: rgb(99 102 241 / .1) var(--tw-gradient-to-position)}.to-indigo-500\/5{--tw-gradient-to: rgb(99 102 241 / .05) var(--tw-gradient-to-position)}.to-indigo-600{--tw-gradient-to: #4f46e5 var(--tw-gradient-to-position)}.to-primary\/60{--tw-gradient-to: hsl(var(--primary) / .6) var(--tw-gradient-to-position)}.to-transparent{--tw-gradient-to: transparent var(--tw-gradient-to-position)}.bg-\[size\:64px_64px\]{background-size:64px 64px}.bg-clip-text{-webkit-background-clip:text;background-clip:text}.fill-current{fill:currentColor}.p-0{padding:0}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-10{padding:2.5rem}.p-12{padding:3rem}.p-2{padding:.5rem}.p-2\.5{padding:.625rem}.p-20{padding:5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-0\.5{padding-left:.125rem;padding-right:.125rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-20{padding-top:5rem;padding-bottom:5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-0{padding-bottom:0}.pb-20{padding-bottom:5rem}.pb-3{padding-bottom:.75rem}.pb-6{padding-bottom:1.5rem}.pl-10{padding-left:2.5rem}.pl-12{padding-left:3rem}.pl-4{padding-left:1rem}.pl-9{padding-left:2.25rem}.pl-\[3\.75rem\]{padding-left:3.75rem}.pr-12{padding-right:3rem}.pr-4{padding-right:1rem}.pt-0{padding-top:0}.pt-1{padding-top:.25rem}.pt-1\.5{padding-top:.375rem}.pt-2{padding-top:.5rem}.pt-24{padding-top:6rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-black{font-weight:900}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.tracking-\[0\.1em\]{letter-spacing:.1em}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-\[0\.3em\]{letter-spacing:.3em}.tracking-\[0\.4em\]{letter-spacing:.4em}.tracking-tight{letter-spacing:-.025em}.tracking-tighter{letter-spacing:-.05em}.tracking-wider{letter-spacing:.05em}.tracking-widest{letter-spacing:.1em}.text-\[\#4A154B\]{--tw-text-opacity: 1;color:rgb(74 21 75 / var(--tw-text-opacity, 1))}.text-\[\#5865F2\]{--tw-text-opacity: 1;color:rgb(88 101 242 / var(--tw-text-opacity, 1))}.text-amber-500{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.text-amber-600{--tw-text-opacity: 1;color:rgb(217 119 6 / var(--tw-text-opacity, 1))}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity, 1))}.text-blue-500{--tw-text-opacity: 1;color:rgb(59 130 246 / var(--tw-text-opacity, 1))}.text-emerald-500{--tw-text-opacity: 1;color:rgb(16 185 129 / var(--tw-text-opacity, 1))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/80{color:hsl(var(--foreground) / .8)}.text-foreground\/90{color:hsl(var(--foreground) / .9)}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-indigo-400{--tw-text-opacity: 1;color:rgb(129 140 248 / var(--tw-text-opacity, 1))}.text-indigo-400\/80{color:#818cf8cc}.text-indigo-500{--tw-text-opacity: 1;color:rgb(99 102 241 / var(--tw-text-opacity, 1))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/20{color:hsl(var(--muted-foreground) / .2)}.text-muted-foreground\/30{color:hsl(var(--muted-foreground) / .3)}.text-muted-foreground\/40{color:hsl(var(--muted-foreground) / .4)}.text-muted-foreground\/50{color:hsl(var(--muted-foreground) / .5)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-orange-500{--tw-text-opacity: 1;color:rgb(249 115 22 / var(--tw-text-opacity, 1))}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-primary\/40{color:hsl(var(--primary) / .4)}.text-primary\/60{color:hsl(var(--primary) / .6)}.text-primary\/80{color:hsl(var(--primary) / .8)}.text-red-400{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.text-red-500\/60{color:#ef444499}.text-red-500\/80{color:#ef4444cc}.text-red-900\/60{color:#7f1d1d99}.text-transparent{color:transparent}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\/80{color:#fffc}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity, 1))}.opacity-0{opacity:0}.opacity-10{opacity:.1}.opacity-20{opacity:.2}.opacity-25{opacity:.25}.opacity-30{opacity:.3}.opacity-5{opacity:.05}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-75{opacity:.75}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_10px_currentColor\]{--tw-shadow: 0 0 10px currentColor;--tw-shadow-colored: 0 0 10px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_12px_rgba\(34\,197\,94\,0\.6\)\]{--tw-shadow: 0 0 12px rgba(34,197,94,.6);--tw-shadow-colored: 0 0 12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_20px_rgba\(var\(--primary-rgb\)\,0\.1\)\]{--tw-shadow: 0 0 20px rgba(var(--primary-rgb),.1);--tw-shadow-colored: 0 0 20px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_8px_rgba\(34\,197\,94\,0\.4\)\]{--tw-shadow: 0 0 8px rgba(34,197,94,.4);--tw-shadow-colored: 0 0 8px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_8px_rgba\(34\,197\,94\,0\.6\)\]{--tw-shadow: 0 0 8px rgba(34,197,94,.6);--tw-shadow-colored: 0 0 8px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-inner{--tw-shadow: inset 0 2px 4px 0 rgb(0 0 0 / .05);--tw-shadow-colored: inset 0 2px 4px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-amber-500\/20{--tw-shadow-color: rgb(245 158 11 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-green-500\/20{--tw-shadow-color: rgb(34 197 94 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-indigo-500\/20{--tw-shadow-color: rgb(99 102 241 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-primary\/10{--tw-shadow-color: hsl(var(--primary) / .1);--tw-shadow: var(--tw-shadow-colored)}.shadow-primary\/20{--tw-shadow-color: hsl(var(--primary) / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-primary\/30{--tw-shadow-color: hsl(var(--primary) / .3);--tw-shadow: var(--tw-shadow-colored)}.shadow-red-500\/20{--tw-shadow-color: rgb(239 68 68 / .2);--tw-shadow: var(--tw-shadow-colored)}.shadow-transparent{--tw-shadow-color: transparent;--tw-shadow: var(--tw-shadow-colored)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-primary{--tw-ring-color: hsl(var(--primary))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.blur-3xl{--tw-blur: blur(64px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-md{--tw-backdrop-blur: blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-xl{--tw-backdrop-blur: blur(24px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-1000{transition-duration:1s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-700{transition-duration:.7s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.scrollbar-thin::-webkit-scrollbar{width:6px;height:6px}.scrollbar-thin::-webkit-scrollbar-track{background:transparent}.scrollbar-thin::-webkit-scrollbar-thumb{border-radius:9999px;background-color:hsl(var(--muted-foreground) / .2);-webkit-transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.scrollbar-thin::-webkit-scrollbar-thumb:hover{background-color:hsl(var(--muted-foreground) / .4)}.scanline{position:relative;overflow:hidden}.scanline:after{content:" ";display:block;position:absolute;top:0;left:0;right:0;bottom:0;background:linear-gradient(to bottom,transparent 50%,rgba(var(--primary),.02) 50%);background-size:100% 4px;z-index:2;pointer-events:none;animation:scanline-move 10s linear infinite}@keyframes scanline-move{0%{background-position:0 0}to{background-position:0 100%}}.glow-pulse{animation:glow-pulse 2.5s ease-in-out infinite}@keyframes glow-pulse{0%,to{opacity:.3;transform:scale(1);filter:blur(2px)}50%{opacity:.7;transform:scale(1.5);filter:blur(4px)}}.card-premium{border-width:1px;border-color:hsl(var(--border) / .5);background-color:hsl(var(--card));--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.3s}.dark .card-premium{background-color:#080c1699;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border-color:#ffffff0d;box-shadow:0 4px 20px #00000080}.dark .card-premium:hover{border-color:#6065f033;box-shadow:0 8px 30px #6366f10d}.animate-in{animation-duration:.4s;animation-timing-function:cubic-bezier(.16,1,.3,1);fill-mode:forwards}@keyframes toast-progress{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.animate-toast-progress{animation:toast-progress 5s linear forwards}.placeholder\:text-muted-foreground\/30::-moz-placeholder{color:hsl(var(--muted-foreground) / .3)}.placeholder\:text-muted-foreground\/30::placeholder{color:hsl(var(--muted-foreground) / .3)}.placeholder\:text-muted-foreground\/40::-moz-placeholder{color:hsl(var(--muted-foreground) / .4)}.placeholder\:text-muted-foreground\/40::placeholder{color:hsl(var(--muted-foreground) / .4)}.last\:hidden:last-child{display:none}.hover\:-translate-y-2:hover{--tw-translate-y: -.5rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-125:hover{--tw-scale-x: 1.25;--tw-scale-y: 1.25;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:scale-\[1\.02\]:hover{--tw-scale-x: 1.02;--tw-scale-y: 1.02;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.hover\:border-primary\/20:hover{border-color:hsl(var(--primary) / .2)}.hover\:border-primary\/30:hover{border-color:hsl(var(--primary) / .3)}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-amber-500:hover{--tw-bg-opacity: 1;background-color:rgb(245 158 11 / var(--tw-bg-opacity, 1))}.hover\:bg-amber-500\/10:hover{background-color:#f59e0b1a}.hover\:bg-amber-500\/20:hover{background-color:#f59e0b33}.hover\:bg-amber-600:hover{--tw-bg-opacity: 1;background-color:rgb(217 119 6 / var(--tw-bg-opacity, 1))}.hover\:bg-background:hover{background-color:hsl(var(--background))}.hover\:bg-blue-500\/10:hover{background-color:#3b82f61a}.hover\:bg-blue-600:hover{--tw-bg-opacity: 1;background-color:rgb(37 99 235 / var(--tw-bg-opacity, 1))}.hover\:bg-emerald-500\/20:hover{background-color:#10b98133}.hover\:bg-green-500\/10:hover{background-color:#22c55e1a}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted\/10:hover{background-color:hsl(var(--muted) / .1)}.hover\:bg-muted\/30:hover{background-color:hsl(var(--muted) / .3)}.hover\:bg-muted\/5:hover{background-color:hsl(var(--muted) / .05)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-muted\/60:hover{background-color:hsl(var(--muted) / .6)}.hover\:bg-muted\/80:hover{background-color:hsl(var(--muted) / .8)}.hover\:bg-primary:hover{background-color:hsl(var(--primary))}.hover\:bg-primary\/10:hover{background-color:hsl(var(--primary) / .1)}.hover\:bg-primary\/20:hover{background-color:hsl(var(--primary) / .2)}.hover\:bg-primary\/5:hover{background-color:hsl(var(--primary) / .05)}.hover\:bg-primary\/\[0\.02\]:hover{background-color:hsl(var(--primary) / .02)}.hover\:bg-red-500:hover{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity, 1))}.hover\:bg-red-500\/10:hover{background-color:#ef44441a}.hover\:bg-red-500\/20:hover{background-color:#ef444433}.hover\:bg-red-600:hover{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity, 1))}.hover\:bg-white\/10:hover{background-color:#ffffff1a}.hover\:bg-white\/\[0\.02\]:hover{background-color:#ffffff05}.hover\:text-amber-500:hover{--tw-text-opacity: 1;color:rgb(245 158 11 / var(--tw-text-opacity, 1))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-primary:hover{color:hsl(var(--primary))}.hover\:text-primary-foreground:hover{color:hsl(var(--primary-foreground))}.hover\:text-red-500:hover{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity, 1))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-2xl:hover{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-md:hover{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-xl:hover{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.hover\:shadow-primary\/20:hover{--tw-shadow-color: hsl(var(--primary) / .2);--tw-shadow: var(--tw-shadow-colored)}.hover\:shadow-primary\/40:hover{--tw-shadow-color: hsl(var(--primary) / .4);--tw-shadow: var(--tw-shadow-colored)}.focus\:border-primary\/50:focus{border-color:hsl(var(--primary) / .5)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-inset:focus{--tw-ring-inset: inset}.focus\:ring-primary:focus{--tw-ring-color: hsl(var(--primary))}.focus\:ring-primary\/20:focus{--tw-ring-color: hsl(var(--primary) / .2)}.focus\:ring-primary\/30:focus{--tw-ring-color: hsl(var(--primary) / .3)}.active\:scale-90:active{--tw-scale-x: .9;--tw-scale-y: .9;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:scale-95:active{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.active\:scale-\[0\.98\]:active{--tw-scale-x: .98;--tw-scale-y: .98;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:hover\:scale-100:hover:disabled{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:rotate-12{--tw-rotate: 12deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:rotate-\[15deg\]{--tw-rotate: 15deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group\/item:hover .group-hover\/item\:scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-105{--tw-scale-x: 1.05;--tw-scale-y: 1.05;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-110{--tw-scale-x: 1.1;--tw-scale-y: 1.1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-150{--tw-scale-x: 1.5;--tw-scale-y: 1.5;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:border-border\/10{border-color:hsl(var(--border) / .1)}.group:hover .group-hover\:border-primary\/20{border-color:hsl(var(--primary) / .2)}.group:hover .group-hover\:bg-primary\/10{background-color:hsl(var(--primary) / .1)}.group:hover .group-hover\:bg-primary\/20{background-color:hsl(var(--primary) / .2)}.group:hover .group-hover\:text-foreground{color:hsl(var(--foreground))}.group:hover .group-hover\:text-primary{color:hsl(var(--primary))}.group\/tile:hover .group-hover\/tile\:opacity-100,.group:hover .group-hover\:opacity-100{opacity:1}.group:hover .group-hover\:opacity-20{opacity:.2}@media(min-width:640px){.sm\:block{display:block}.sm\:inline{display:inline}.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:p-6{padding:1.5rem}.sm\:p-8{padding:2rem}}@media(min-width:768px){.md\:col-span-2{grid-column:span 2 / span 2}.md\:inline{display:inline}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:p-10{padding:2.5rem}}@media(min-width:1024px){.lg\:col-span-1{grid-column:span 1 / span 1}.lg\:col-span-2{grid-column:span 2 / span 2}.lg\:inline{display:inline}.lg\:flex{display:flex}.lg\:grid{display:grid}.lg\:h-\[600px\]{height:600px}.lg\:h-full{height:100%}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.lg\:grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}}@media(min-width:1280px){.xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(prefers-color-scheme:dark){.dark\:bg-card{background-color:hsl(var(--card))}.dark\:text-\[\#E01E5A\]{--tw-text-opacity: 1;color:rgb(224 30 90 / var(--tw-text-opacity, 1))}.dark\:text-amber-400{--tw-text-opacity: 1;color:rgb(251 191 36 / var(--tw-text-opacity, 1))}.dark\:text-red-400\/60{color:#f8717199}}
|
package/docker-compose.yml
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
version: '3.8'
|
|
2
|
-
|
|
3
|
-
services:
|
|
4
|
-
# Main Persistence for Archive
|
|
5
|
-
mysql:
|
|
6
|
-
image: mysql:8.0
|
|
7
|
-
container_name: flux-mysql
|
|
8
|
-
ports:
|
|
9
|
-
- "3306:3306"
|
|
10
|
-
environment:
|
|
11
|
-
MYSQL_ROOT_PASSWORD: root
|
|
12
|
-
MYSQL_DATABASE: flux
|
|
13
|
-
healthcheck:
|
|
14
|
-
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
|
|
15
|
-
timeout: 20s
|
|
16
|
-
retries: 10
|
|
17
|
-
|
|
18
|
-
# Real-time state store
|
|
19
|
-
redis:
|
|
20
|
-
image: redis:7-alpine
|
|
21
|
-
container_name: flux-redis
|
|
22
|
-
ports:
|
|
23
|
-
- "6379:6379"
|
|
24
|
-
# Flux Console (Optional: run locally via npm dev instead)
|
|
25
|
-
# console:
|
|
26
|
-
# build: .
|
|
27
|
-
# ports:
|
|
28
|
-
# - "3000:3000"
|
|
29
|
-
# environment:
|
|
30
|
-
# - REDIS_URL=redis://redis:6379
|
|
31
|
-
# - DB_DRIVER=mysql
|
|
32
|
-
# - DB_HOST=mysql
|
|
33
|
-
# - DB_USER=root
|
|
34
|
-
# - DB_PASSWORD=root
|
|
35
|
-
# - DB_NAME=flux
|
|
36
|
-
# depends_on:
|
|
37
|
-
# mysql:
|
|
38
|
-
# condition: service_healthy
|
|
39
|
-
# redis:
|
|
40
|
-
# condition: service_started
|
package/docs/ALERTING_GUIDE.md
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# 🔔 Zenith Alerting Guide
|
|
2
|
-
|
|
3
|
-
This guide explains how to configure and manage the alerting system in Zenith to ensure your infrastructure and queues remain healthy.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🚀 Overview
|
|
8
|
-
|
|
9
|
-
Zenith's alerting engine is **Redis-Native** and **Stateless**.
|
|
10
|
-
* **Persistence**: Rules are stored in Redis (`gravito:zenith:alerts:rules`).
|
|
11
|
-
* **Evaluation**: The server evaluates all rules every 2 seconds against real-time metrics.
|
|
12
|
-
* **Delivery**: Alerts are dispatched via Slack Webhooks.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## 🛠️ Configuration Fields
|
|
17
|
-
|
|
18
|
-
When adding a new rule in **Settings > Alerting**, you will encounter these fields:
|
|
19
|
-
|
|
20
|
-
### 1. Rule Name
|
|
21
|
-
A descriptive label for the alert (e.g., `Critical Backlog`, `Agent Offline`). This name will appear in the Slack notification.
|
|
22
|
-
|
|
23
|
-
### 2. Type (Metric Category)
|
|
24
|
-
* **Queue Backlog**: Monitors the number of jobs in the `waiting` state.
|
|
25
|
-
* **High Failure Count**: Monitors the number of jobs in the `failed` state.
|
|
26
|
-
* **Worker Loss**: Monitors the total number of active worker nodes.
|
|
27
|
-
* **Node CPU (%)**: Monitors process-level CPU usage reported by Quasar Agents.
|
|
28
|
-
* **Node RAM (%)**: Monitors process-level RAM usage (RSS) relative to system total.
|
|
29
|
-
|
|
30
|
-
### 3. Threshold
|
|
31
|
-
The numeric value that triggers the alert.
|
|
32
|
-
* For **Backlog/Failure**: The number of jobs (e.g., `1000`).
|
|
33
|
-
* For **CPU/RAM**: The percentage (e.g., `90`).
|
|
34
|
-
* For **Worker Loss**: The *minimum* number of workers expected (e.g., alert triggers if count is `< 2`).
|
|
35
|
-
|
|
36
|
-
### 4. Cooldown (Minutes)
|
|
37
|
-
**Crucial Concept**: The period the system "stays silent" after an alert is fired.
|
|
38
|
-
* **Logic**: Once a rule triggers and sends a notification, it enters a "lock" state for the duration of the cooldown.
|
|
39
|
-
* **Purpose**: Prevents "Alert Fatigue" and notification storms.
|
|
40
|
-
* **Example**: If set to `30`, and a backlog spike occurs, you get **one** notification. You won't get another one for the same rule for 30 minutes, even if the backlog remains high.
|
|
41
|
-
|
|
42
|
-
### 5. Queue (Optional)
|
|
43
|
-
Specify a specific queue name (e.g., `orders`, `emails`) to monitor. If left empty, the rule applies to the **total sum** of all queues.
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## 🌊 Best Practices
|
|
48
|
-
|
|
49
|
-
### The "Instant Fire" Design
|
|
50
|
-
Zenith alerts are designed for **instant awareness**.
|
|
51
|
-
* If a threshold is met during a 2-second check, the alert fires **immediately**.
|
|
52
|
-
* It does **not** wait for the condition to persist for multiple minutes (Debouncing).
|
|
53
|
-
* **Pro Tip**: If you have frequent "tiny spikes" that resolve themselves in seconds, set your **Threshold** slightly higher than the spikes to avoid noise.
|
|
54
|
-
|
|
55
|
-
### Recommended Settings
|
|
56
|
-
|
|
57
|
-
| Scenario | Type | Threshold | Cooldown |
|
|
58
|
-
| :--- | :--- | :--- | :--- |
|
|
59
|
-
| **Critical Failure** | High Failure Count | 50 | 15m |
|
|
60
|
-
| **System Overload** | Node CPU | 90 | 30m |
|
|
61
|
-
| **Quiet Hours** | Queue Backlog | 5000 | 120m |
|
|
62
|
-
| **Fatal Shutdown** | Worker Loss | 1 | 10m |
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 🔗 Slack Integration
|
|
67
|
-
To receive notifications, ensure the `SLACK_WEBHOOK_URL` environment variable is set before starting the Zenith server.
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
export SLACK_WEBHOOK_URL=https://hooks.slack.com/services/Txxx/Bxxx/Xxxx
|
|
71
|
-
```
|
package/docs/DEPLOYMENT.md
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
# Flux Console Deployment Guide
|
|
2
|
-
|
|
3
|
-
This whitepaper outlines the recommended deployment strategies for Gravito Flux Console in various environments, from local development to enterprise-scale production clusters.
|
|
4
|
-
|
|
5
|
-
## 1. Deployment Philosophy: "Zero-Config, Anywhere"
|
|
6
|
-
|
|
7
|
-
Flux Console is designed to be infrastructure-agnostic. It acts as a stateless monitoring interface that connects to your existing infrastructure (Redis). It does not require its own dedicated database for basic operation.
|
|
8
|
-
|
|
9
|
-
### Core Dependencies
|
|
10
|
-
- **Runtime**: Node.js 18+ OR Bun 1.0+ (or use standard binary)
|
|
11
|
-
- **Infrastructure**: Redis 6.0+ (Required for state coordination)
|
|
12
|
-
- **Optional**: SQL Database (MySQL/PostgreSQL) for History Persistence (Future Feature)
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## 2. Deployment Scenarios
|
|
17
|
-
|
|
18
|
-
### Scenario A: Local Development (The "NPM" Way)
|
|
19
|
-
Best for individual developers debugging workers locally.
|
|
20
|
-
|
|
21
|
-
**Prerequisites:** Node.js or Bun installed.
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
# S1. Run directly via npx (Zero Installation)
|
|
25
|
-
npx @gravito/flux-console
|
|
26
|
-
# Automatically detects local Redis at localhost:6379 and opens browser.
|
|
27
|
-
|
|
28
|
-
# S2. Install globally for frequent use
|
|
29
|
-
npm install -g @gravito/flux-console
|
|
30
|
-
flux-console start
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Scenario B: Traditional VM / EC2 (The "Process" Way)
|
|
34
|
-
Best for bare-metal servers or performance-critical environments where avoiding Docker overhead is desired.
|
|
35
|
-
|
|
36
|
-
**Option 1: Node.js + PM2 (Recommended)**
|
|
37
|
-
```bash
|
|
38
|
-
# 1. Install globally
|
|
39
|
-
npm install -g @gravito/flux-console pm2
|
|
40
|
-
|
|
41
|
-
# 2. Start with PM2 for auto-restart and log management
|
|
42
|
-
pm2 start flux-console --name flux-monitor -- --port 3000
|
|
43
|
-
|
|
44
|
-
# 3. Configure Env Vars (if Redis is remote)
|
|
45
|
-
pm2 set flux-monitor:env.REDIS_URL redis://prod-redis:6379
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
**Option 2: Standalone Binary (The "Go" Way)**
|
|
49
|
-
*Ideal for restricted environments without Node.js installed.*
|
|
50
|
-
1. Download the binary: `flux-console-linux-x64`
|
|
51
|
-
2. `chmod +x ./flux-console-linux-x64`
|
|
52
|
-
3. `./flux-console-linux-x64`
|
|
53
|
-
|
|
54
|
-
### Scenario C: Docker & Container Platforms (The "Cloud-Native" Way)
|
|
55
|
-
Best for Kubernetes, AWS ECS, Google Cloud Run, or simple Docker Compose setups.
|
|
56
|
-
|
|
57
|
-
**1. Docker Run**
|
|
58
|
-
```bash
|
|
59
|
-
docker run -d \
|
|
60
|
-
-p 3000:3000 \
|
|
61
|
-
-e REDIS_URL=redis://your-redis-host:6379 \
|
|
62
|
-
-e AUTH_SECRET=my-super-secret-password \
|
|
63
|
-
--name flux-console \
|
|
64
|
-
gravito/flux-console:latest
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**2. Docker Compose (Full Stack Example)**
|
|
68
|
-
```yaml
|
|
69
|
-
version: '3.8'
|
|
70
|
-
services:
|
|
71
|
-
redis:
|
|
72
|
-
image: redis:alpine
|
|
73
|
-
ports:
|
|
74
|
-
- "6379:6379"
|
|
75
|
-
|
|
76
|
-
flux-console:
|
|
77
|
-
image: gravito/flux-console:latest
|
|
78
|
-
ports:
|
|
79
|
-
- "3000:3000"
|
|
80
|
-
environment:
|
|
81
|
-
- REDIS_URL=redis://redis:6379
|
|
82
|
-
- PORT=3000
|
|
83
|
-
depends_on:
|
|
84
|
-
- redis
|
|
85
|
-
|
|
86
|
-
# Your Application Workers
|
|
87
|
-
worker-orders:
|
|
88
|
-
build: .
|
|
89
|
-
command: npm run start:worker
|
|
90
|
-
environment:
|
|
91
|
-
- REDIS_URL=redis://redis:6379
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
**3. Kubernetes (K8s)**
|
|
95
|
-
Deploy as a simple Deployment + Service.
|
|
96
|
-
|
|
97
|
-
```yaml
|
|
98
|
-
apiVersion: apps/v1
|
|
99
|
-
kind: Deployment
|
|
100
|
-
metadata:
|
|
101
|
-
name: flux-console
|
|
102
|
-
spec:
|
|
103
|
-
replicas: 1
|
|
104
|
-
selector:
|
|
105
|
-
matchLabels:
|
|
106
|
-
app: flux-console
|
|
107
|
-
template:
|
|
108
|
-
metadata:
|
|
109
|
-
labels:
|
|
110
|
-
app: flux-console
|
|
111
|
-
spec:
|
|
112
|
-
containers:
|
|
113
|
-
- name: flux-console
|
|
114
|
-
image: gravito/flux-console:latest
|
|
115
|
-
env:
|
|
116
|
-
- name: REDIS_URL
|
|
117
|
-
valueFrom:
|
|
118
|
-
secretKeyRef:
|
|
119
|
-
name: redis-secrets
|
|
120
|
-
key: url
|
|
121
|
-
ports:
|
|
122
|
-
- containerPort: 3000
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
---
|
|
126
|
-
|
|
127
|
-
## 3. Security Best Practices
|
|
128
|
-
|
|
129
|
-
Since Flux Console provides administrative capabilities (Pause Queue, Retry Job, Delete Job), security is paramount in production.
|
|
130
|
-
|
|
131
|
-
1. **Network Isolation (Private VPC)**:
|
|
132
|
-
- **Recommendation**: Do NOT expose Flux Console to the public internet.
|
|
133
|
-
- Deploy it within your VPN / Private Subnet.
|
|
134
|
-
- Access via VPN or SSH Tunnel.
|
|
135
|
-
|
|
136
|
-
2. **Authentication**:
|
|
137
|
-
- Enable built-in simple auth by setting `AUTH_PASSWORD` env var.
|
|
138
|
-
- For enterprise, put it behind an Identity Aware Proxy (e.g., Cloudflare Access, AWS ALB OIDC) to enforce SSO (Google/Okta) login.
|
|
139
|
-
|
|
140
|
-
3. **Read-Only Mode (Future Feature)**:
|
|
141
|
-
- For giving access to support teams, run a separate instance with `READ_ONLY=true` env var (Roadmap item).
|
|
142
|
-
|
|
143
|
-
## 4. Scaling (High Availability)
|
|
144
|
-
|
|
145
|
-
Flux Console is **stateless**. You can run multiple instances behind a Load Balancer for high availability.
|
|
146
|
-
|
|
147
|
-
- **Session Affinity**: Not required (JWT based Auth).
|
|
148
|
-
- **Resource Usage**: Very low (mostly forwarding Redis data). A standard `t3.micro` or `256MB` container is usually sufficient for monitoring even large clusters.
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
## 5. Troubleshooting
|
|
153
|
-
|
|
154
|
-
**Common Issue: "Cannot connect to Redis"**
|
|
155
|
-
- **Docker**: Ensure you use the service name (e.g., `redis`) not `localhost` if inside the same network. Host networking might be needed for accessing host Redis.
|
|
156
|
-
- **AWS ElastiCache**: Ensure Security Groups allow traffic on port 6379 from the Console's security group.
|
|
157
|
-
- **Encryption**: If Redis uses TLS (rediss://), ensure certificates are trusted or use `REDIS_TLS_REJECT_UNAUTHORIZED=0` (not recommended for prod).
|
package/docs/DOCS_INTERNAL.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# Internal Technical Documentation
|
|
2
|
-
|
|
3
|
-
This document records technical implementations for Dead Letter Queues (DLQ) and Worker Metrics within the Flux system.
|
|
4
|
-
|
|
5
|
-
## 1. Dead Letter Queue (DLQ)
|
|
6
|
-
|
|
7
|
-
### Storage (Redis)
|
|
8
|
-
Failed jobs are moved to a specific list with the suffix `:failed`.
|
|
9
|
-
- **Key**: `{queue}:failed`
|
|
10
|
-
- **Cap**: 1,000 items (capped via `LTRIM` in `RedisDriver.fail`).
|
|
11
|
-
|
|
12
|
-
### Life Cycle
|
|
13
|
-
1. `Worker` attempts to process a job.
|
|
14
|
-
2. On failure, `Worker` calculates retry delay using `job.getRetryDelay(attempt)`.
|
|
15
|
-
3. If `attempt >= maxAttempts`, `Consumer` catches the error.
|
|
16
|
-
4. `Consumer` calls `QueueManager.fail(job, error)`.
|
|
17
|
-
5. Driver pushes the job to the `:failed` list with `error` and `failedAt` metadata.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## 2. Worker Metrics
|
|
22
|
-
|
|
23
|
-
Workers report health metrics during their heartbeat cycle (default: every 5s).
|
|
24
|
-
|
|
25
|
-
### Metric Payload Schema
|
|
26
|
-
```json
|
|
27
|
-
{
|
|
28
|
-
"cpu": 0.15, // Load average (normalized by cores)
|
|
29
|
-
"ram": {
|
|
30
|
-
"rss": 120, // Resident Set Size (MB)
|
|
31
|
-
"heapUsed": 45, // V8 Heap Used (MB)
|
|
32
|
-
"heapTotal": 64 // V8 Heap Total (MB)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
### Storage
|
|
38
|
-
In Redis, metrics are stored as part of the `flux_console:workers:{id}` hash.
|
|
39
|
-
- **Field**: `metrics` (JSON string)
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## 3. Bulk Retry Logic (Lua)
|
|
44
|
-
|
|
45
|
-
To ensure atomicity and performance, bulk retries of failed jobs use Lua scripts.
|
|
46
|
-
|
|
47
|
-
### Retry All Script
|
|
48
|
-
Moves all elements from `{queue}:failed` to `{queue}` then deletes the failed list.
|
|
49
|
-
```lua
|
|
50
|
-
local jobs = redis.call('LRANGE', KEYS[1], 0, -1)
|
|
51
|
-
for i, job in ipairs(jobs) do
|
|
52
|
-
redis.call('RPUSH', KEYS[2], job)
|
|
53
|
-
end
|
|
54
|
-
redis.call('DEL', KEYS[1])
|
|
55
|
-
return #jobs
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## 4. System Logs & Archiving
|
|
61
|
-
|
|
62
|
-
To maintain a permanent record of system events while keeping Redis memory usage low, Flux Console uses an asynchronous archiving pattern.
|
|
63
|
-
|
|
64
|
-
### Live Logs (Redis)
|
|
65
|
-
* **Key**: `flux_console:logs:system` (List)
|
|
66
|
-
* **Strategy**: LILO (Last-In-Last-Out) capped at 100 items.
|
|
67
|
-
* **Update**: Every `publishLog` call pushes to this list and trims it.
|
|
68
|
-
|
|
69
|
-
### Persistent Archiving (SQL)
|
|
70
|
-
* **Trigger**: Every `QueueService.publishLog` call asynchronously sends the log to the configured `PersistenceAdapter`.
|
|
71
|
-
* **Table**: `flux_system_logs` (MySQL or SQLite).
|
|
72
|
-
* **Search**: The `/api/logs/archive` endpoint performs direct SQL queries with filters on `level`, `worker_id`, `queue`, and `message` content.
|
|
73
|
-
* **Retention**: Cleanup is handled via `PersistenceAdapter.cleanup`, removing logs older than the configured threshold (default: 30 days).
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# 🚀 Project Zenith: Laravel Integration Roadmap
|
|
2
|
-
|
|
3
|
-
**Repository**: `gravito-framework/laravel-zenith`
|
|
4
|
-
**Target Audience**: Laravel 10/11 Applications
|
|
5
|
-
**Goal**: Provide deep, native introspection into Laravel applications for Gravito Zenith.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 1. Vision & Architecture
|
|
10
|
-
|
|
11
|
-
Unlike the **Quasar Agent** (which is a sidecar daemon for OS/Infrastructure monitoring), **Laravel Zenith** is a native Composer package that lives *inside* the application.
|
|
12
|
-
|
|
13
|
-
* **Role**: " The Reporter". It sees what the OS cannot see.
|
|
14
|
-
* **Transport**: Direct Redis connection (utilizing `swarrot` or standard `predis`/`phpredis`).
|
|
15
|
-
* **Philosophy**: Zero-blocking. All reporting should be "fire-and-forget" or queued to avoid slowing down the user request lifecycle.
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 2. Core Features (The "Why")
|
|
20
|
-
|
|
21
|
-
### A. Live Operational Logs (`logs`)
|
|
22
|
-
* **Feature**: A custom `Log Channel` driver.
|
|
23
|
-
* **Goal**: Stream logs (Info/Error/Debug) directly to Zenith's Live Log view.
|
|
24
|
-
* **Implementation**:
|
|
25
|
-
* `config/logging.php`: Add a `zenith` channel.
|
|
26
|
-
* Push JSON payloads to `flux_console:logs` Redis channel.
|
|
27
|
-
|
|
28
|
-
### B. Queue Lifecycle Events (`queues`)
|
|
29
|
-
* **Feature**: Listen to Laravel Queue Events (`JobProcessing`, `JobProcessed`, `JobFailed`).
|
|
30
|
-
* **Goal**: Provide granular job insight that `quasar-go` cannot (e.g., "Job X failed with Exception Y", "Job Z took 45s").
|
|
31
|
-
* **Implementation**:
|
|
32
|
-
* Event Subscriber for `Illuminate\Queue\Events\*`.
|
|
33
|
-
* Capture `job->getRawBody()`, `exception->getMessage()`.
|
|
34
|
-
|
|
35
|
-
### C. Request Performance (`http`)
|
|
36
|
-
* **Feature**: Global Middleware (`ZenithMonitorMiddleware`).
|
|
37
|
-
* **Goal**: Track "Slow Requests", 500 Errors, and Throughput.
|
|
38
|
-
* **Metrics**:
|
|
39
|
-
* Status Codes (2xx, 4xx, 5xx).
|
|
40
|
-
* Duration (ms).
|
|
41
|
-
* Route Name / Controller Action.
|
|
42
|
-
|
|
43
|
-
### D. System Health Checks
|
|
44
|
-
* **Feature**: `php artisan zenith:check`
|
|
45
|
-
* **Goal**: Verify Redis connection and permissions.
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## 3. Implementation Roadmap
|
|
50
|
-
|
|
51
|
-
### Phase 1: The Foundation (Logs & Config)
|
|
52
|
-
**Goal**: Get the package installed and streaming basic logs.
|
|
53
|
-
- [ ] Initialize Repository `gravito-framework/laravel-zenith`.
|
|
54
|
-
- [ ] Create `ZenithServiceProvider`.
|
|
55
|
-
- [ ] Implement `ZenithLogger` (Monolog Handler).
|
|
56
|
-
- [ ] Publishing `config/zenith.php` (Redis connection settings).
|
|
57
|
-
- [ ] **Deliverable**: `Log::info('Hello Zenith')` appears in Zenith UI.
|
|
58
|
-
|
|
59
|
-
### Phase 2: The Worker's Eye (Queues)
|
|
60
|
-
**Goal**: Deep visibility into Queue Jobs.
|
|
61
|
-
- [ ] Create `ZenithQueueSubscriber`.
|
|
62
|
-
- [ ] Handle `JobFailed`: Serialize exception and push to Zenith Alerting.
|
|
63
|
-
- [ ] Handle `JobProcessed`: Record metrics for "Jobs per minute".
|
|
64
|
-
- [ ] **Deliverable**: Seeing real-time "Job Completed" toasts and Error details in Zenith.
|
|
65
|
-
|
|
66
|
-
### Phase 3: The Watchtower (HTTP & Exceptions)
|
|
67
|
-
**Goal**: Monitoring web requests.
|
|
68
|
-
- [ ] Create `RecordRequestMetrics` Middleware.
|
|
69
|
-
- [ ] Exception Handler integration (optional, for global error catching).
|
|
70
|
-
- [ ] Filter logic (ignore `/nova`, `/telescope`, etc.).
|
|
71
|
-
- [ ] **Deliverable**: HTTP Throughput graphs in Zenith.
|
|
72
|
-
|
|
73
|
-
### Phase 4: The Bridge (Remote Control Hooks)
|
|
74
|
-
**Goal**: Allow Zenith to trigger Laravel actions safely.
|
|
75
|
-
- [ ] Expose internal hooks for `quasar-go` to call?
|
|
76
|
-
* *Note*: `quasar-go` already calls `artisan`. Phase 4 might be about ensuring `artisan zenith:run-job {id}` exists if we need advanced job re-running that `queue:retry` can't handle.
|
|
77
|
-
|
|
78
|
-
---
|
|
79
|
-
|
|
80
|
-
## 4. Technical Specifications
|
|
81
|
-
|
|
82
|
-
### Redis Protocol
|
|
83
|
-
We will reuse the **Gravito Pulse Protocol (GPP)** used by `quasar-go`:
|
|
84
|
-
* **Logs**: `PUBLISH flux_console:logs`
|
|
85
|
-
* **Metrics**: `INCR flux_console:metrics:...`
|
|
86
|
-
|
|
87
|
-
### Configuration (`zenith.php`)
|
|
88
|
-
```php
|
|
89
|
-
return [
|
|
90
|
-
'enabled' => env('ZENITH_ENABLED', true),
|
|
91
|
-
|
|
92
|
-
'connection' => env('ZENITH_REDIS_CONNECTION', 'default'),
|
|
93
|
-
|
|
94
|
-
'logging' => [
|
|
95
|
-
'enabled' => true,
|
|
96
|
-
'level' => 'debug',
|
|
97
|
-
],
|
|
98
|
-
|
|
99
|
-
'queues' => [
|
|
100
|
-
'monitor_all' => true,
|
|
101
|
-
'ignore_jobs' => [],
|
|
102
|
-
],
|
|
103
|
-
];
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Dependency Strategy
|
|
107
|
-
* **Support**: Laravel 10.x, 11.x
|
|
108
|
-
* **Php**: 8.1+
|
|
109
|
-
* **Driver**: `phpredis` (preferred) or `predis`.
|