aegis-stack 0.2.0rc2__py3-none-any.whl

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.
Files changed (392) hide show
  1. aegis/__init__.py +5 -0
  2. aegis/__main__.py +51 -0
  3. aegis/cli/__init__.py +6 -0
  4. aegis/cli/callbacks.py +114 -0
  5. aegis/cli/interactive.py +611 -0
  6. aegis/cli/utils.py +70 -0
  7. aegis/cli/validators.py +34 -0
  8. aegis/commands/__init__.py +6 -0
  9. aegis/commands/add.py +353 -0
  10. aegis/commands/add_service.py +332 -0
  11. aegis/commands/components.py +35 -0
  12. aegis/commands/init.py +370 -0
  13. aegis/commands/remove.py +227 -0
  14. aegis/commands/services.py +52 -0
  15. aegis/commands/update.py +252 -0
  16. aegis/commands/version.py +12 -0
  17. aegis/config/__init__.py +1 -0
  18. aegis/config/shared_files.py +136 -0
  19. aegis/core/CLAUDE.md +377 -0
  20. aegis/core/__init__.py +6 -0
  21. aegis/core/component_files.py +228 -0
  22. aegis/core/component_utils.py +220 -0
  23. aegis/core/components.py +127 -0
  24. aegis/core/copier_manager.py +315 -0
  25. aegis/core/copier_updater.py +475 -0
  26. aegis/core/dependency_resolver.py +119 -0
  27. aegis/core/manual_updater.py +554 -0
  28. aegis/core/post_gen_tasks.py +547 -0
  29. aegis/core/service_resolver.py +261 -0
  30. aegis/core/services.py +157 -0
  31. aegis/core/template_generator.py +266 -0
  32. aegis/core/version_compatibility.py +259 -0
  33. aegis/templates/CLAUDE.md +591 -0
  34. aegis/templates/cookiecutter-aegis-project/cookiecutter.json +39 -0
  35. aegis/templates/cookiecutter-aegis-project/hooks/post_gen_project.py +214 -0
  36. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.dockerignore +71 -0
  37. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.env.example.j2 +130 -0
  38. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/.gitignore +131 -0
  39. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Dockerfile +53 -0
  40. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/Makefile +236 -0
  41. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/README.md.j2 +196 -0
  42. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/alembic.ini.j2 +111 -0
  43. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/env.py.j2 +91 -0
  44. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/script.py.mako +25 -0
  45. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/alembic/versions/001_initial_auth.py.j2 +51 -0
  46. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/__init__.py +5 -0
  47. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/__init__.py +6 -0
  48. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/ai.py.j2 +700 -0
  49. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/ai_rendering.py +361 -0
  50. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/auth.py.j2 +253 -0
  51. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/health.py.j2 +419 -0
  52. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/load_test.py.j2 +656 -0
  53. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/main.py.j2 +65 -0
  54. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/marko_terminal_renderer.py +489 -0
  55. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/tasks.py.j2 +328 -0
  56. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/cli/{% if cookiecutter.include_scheduler == /"yes/" %}tasks.py{% endif %}" +340 -0
  57. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/__init__.py +0 -0
  58. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/__init__.py +0 -0
  59. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/ai/__init__.py +8 -0
  60. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/ai/router.py +329 -0
  61. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/__init__.py +1 -0
  62. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/auth/router.py +64 -0
  63. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/deps.py +58 -0
  64. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/health.py +163 -0
  65. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/models.py.j2 +280 -0
  66. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/routing.py.j2 +32 -0
  67. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/scheduler.py.j2 +121 -0
  68. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/api/worker.py.j2 +478 -0
  69. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/hooks.py +144 -0
  70. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/main.py +31 -0
  71. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/__init__.py +1 -0
  72. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/middleware/cors.py +20 -0
  73. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/__init__.py +1 -0
  74. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/shutdown/cleanup.py +14 -0
  75. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/__init__.py +1 -0
  76. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/component_health.py.j2 +418 -0
  77. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/backend/startup/database_init.py.j2 +83 -0
  78. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/__init__.py +5 -0
  79. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/__init__.py +27 -0
  80. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/table.py +78 -0
  81. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/controls/text.py +142 -0
  82. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/__init__.py.j2 +47 -0
  83. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
  84. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
  85. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/base_card.py +256 -0
  86. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
  87. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
  88. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/database_card.py +420 -0
  89. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
  90. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
  91. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
  92. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
  93. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/services_card.py +233 -0
  94. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
  95. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/main.py.j2 +653 -0
  96. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/frontend/theme.py +48 -0
  97. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/__init__.py +1 -0
  98. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/scheduler/main.py.j2 +156 -0
  99. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/CLAUDE.md.j2 +213 -0
  100. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/__init__.py +6 -0
  101. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/constants.py.j2 +30 -0
  102. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/pools.py +97 -0
  103. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/__init__.py +1 -0
  104. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/load_test.py +55 -0
  105. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/media.py +49 -0
  106. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/queues/system.py +44 -0
  107. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/registry.py +139 -0
  108. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/__init__.py +120 -0
  109. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/load_tasks.py +507 -0
  110. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/simple_system_tasks.py +33 -0
  111. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/components/worker/tasks/system_tasks.py +281 -0
  112. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/config.py.j2 +178 -0
  113. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/constants.py +58 -0
  114. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/db.py.j2 +176 -0
  115. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/log.py +92 -0
  116. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/core/security.py +62 -0
  117. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/__init__.py +1 -0
  118. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/webserver.py +40 -0
  119. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/entrypoints/{% if cookiecutter.include_scheduler == /"yes/" %}scheduler.py{% endif %}" +21 -0
  120. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/__init__.py +0 -0
  121. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/integrations/main.py +62 -0
  122. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/__init__.py +1 -0
  123. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/models/user.py +44 -0
  124. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/py.typed +0 -0
  125. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/__init__.py +1 -0
  126. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/__init__.py +8 -0
  127. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/config.py +130 -0
  128. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/conversation.py +213 -0
  129. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/health.py +96 -0
  130. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/models.py +229 -0
  131. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/providers.py +370 -0
  132. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/ai/service.py +388 -0
  133. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/__init__.py +1 -0
  134. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/auth_service.py +41 -0
  135. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/health.py +164 -0
  136. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/auth/user_service.py +83 -0
  137. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/middleware_inspector.py.j2 +223 -0
  138. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/models.py.j2 +70 -0
  139. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/backend/route_inspector.py.j2 +155 -0
  140. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test.py +679 -0
  141. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/load_test_models.py +266 -0
  142. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/__init__.py.j2 +21 -0
  143. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/models.py.j2 +119 -0
  144. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/scheduled_task_manager.py.j2 +273 -0
  145. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/scheduler/task_monitor.py.j2 +189 -0
  146. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/__init__.py +15 -0
  147. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/shared/models.py +26 -0
  148. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/__init__.py +52 -0
  149. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/alerts.py +94 -0
  150. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/backup.py.j2 +119 -0
  151. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/health.py.j2 +1333 -0
  152. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/models.py +243 -0
  153. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/app/services/system/ui.py +52 -0
  154. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-dark.png +0 -0
  155. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto-square-backup.png +0 -0
  156. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/assets/aegis-manifesto.png +0 -0
  157. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.dockerignore +71 -0
  158. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.env.example.j2 +64 -0
  159. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/.gitignore +131 -0
  160. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Dockerfile +53 -0
  161. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/Makefile +211 -0
  162. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/README.md.j2 +172 -0
  163. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/docker-compose.yml.j2 +78 -0
  164. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/mkdocs.yml.j2 +62 -0
  165. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/pyproject.toml.j2 +120 -0
  166. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/clean-validation/uv.lock +1673 -0
  167. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docker-compose.yml.j2 +200 -0
  168. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/api.md +191 -0
  169. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md +0 -0
  170. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/components/scheduler.md.j2 +621 -0
  171. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/development.md +215 -0
  172. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/health.md +240 -0
  173. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/javascripts/mermaid-config.js +62 -0
  174. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/docs/stylesheets/mermaid.css +95 -0
  175. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/mkdocs.yml.j2 +62 -0
  176. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/pyproject.toml.j2 +131 -0
  177. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh +87 -0
  178. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/entrypoint.sh.j2 +93 -0
  179. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/scripts/gen_docs.py +16 -0
  180. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/__init__.py +1 -0
  181. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_auth_endpoints.py.j2 +307 -0
  182. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_health_endpoints.py.j2 +262 -0
  183. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_scheduler_endpoints.py.j2 +214 -0
  184. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/api/test_worker_endpoints.py.j2 +165 -0
  185. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_ai_rendering.py +427 -0
  186. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/cli/test_conversation_memory.py +465 -0
  187. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/components/test_scheduler.py +43 -0
  188. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/conftest.py.j2 +195 -0
  189. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/__init__.py +1 -0
  190. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/__init__.py +1 -0
  191. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/conftest.py +78 -0
  192. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_health.py +157 -0
  193. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_models.py +164 -0
  194. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/ai/test_service.py +198 -0
  195. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_auth_integration.py.j2 +528 -0
  196. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_component_integration.py.j2 +387 -0
  197. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_conversation_persistence.py +342 -0
  198. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_health_logic.py.j2 +663 -0
  199. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_models.py +619 -0
  200. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_load_test_service.py +603 -0
  201. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_middleware_inspector.py.j2 +248 -0
  202. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_scheduled_task_manager.py.j2 +292 -0
  203. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_system_service.py +98 -0
  204. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/services/test_worker_health_registration.py.j2 +257 -0
  205. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/tests/test_core.py +49 -0
  206. aegis/templates/cookiecutter-aegis-project/{{cookiecutter.project_slug}}/uv.lock +1673 -0
  207. aegis/templates/copier-aegis-project/{{ project_slug }}/.copier-answers.yml.jinja +21 -0
  208. aegis/templates/copier-aegis-project/{{ project_slug }}/.dockerignore +71 -0
  209. aegis/templates/copier-aegis-project/{{ project_slug }}/.env.example.jinja +130 -0
  210. aegis/templates/copier-aegis-project/{{ project_slug }}/.gitignore +131 -0
  211. aegis/templates/copier-aegis-project/{{ project_slug }}/Dockerfile +53 -0
  212. aegis/templates/copier-aegis-project/{{ project_slug }}/Makefile.jinja +236 -0
  213. aegis/templates/copier-aegis-project/{{ project_slug }}/README.md.jinja +196 -0
  214. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/alembic.ini.jinja +111 -0
  215. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/env.py.jinja +91 -0
  216. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/script.py.mako +25 -0
  217. aegis/templates/copier-aegis-project/{{ project_slug }}/alembic/versions/001_initial_auth.py.jinja +51 -0
  218. aegis/templates/copier-aegis-project/{{ project_slug }}/app/__init__.py.jinja +5 -0
  219. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/__init__.py.jinja +6 -0
  220. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai.py.jinja +700 -0
  221. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/ai_rendering.py +360 -0
  222. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/auth.py.jinja +253 -0
  223. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/health.py.jinja +419 -0
  224. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/load_test.py.jinja +656 -0
  225. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/main.py.jinja +65 -0
  226. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/marko_terminal_renderer.py +489 -0
  227. aegis/templates/copier-aegis-project/{{ project_slug }}/app/cli/tasks.py.jinja +328 -0
  228. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/__init__.py +0 -0
  229. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/__init__.py +0 -0
  230. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/__init__.py +8 -0
  231. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/ai/router.py +329 -0
  232. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/__init__.py +1 -0
  233. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/auth/router.py +64 -0
  234. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/deps.py +58 -0
  235. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/health.py.jinja +163 -0
  236. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/models.py.jinja +280 -0
  237. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/routing.py.jinja +32 -0
  238. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/scheduler.py.jinja +121 -0
  239. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/api/worker.py.jinja +478 -0
  240. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/hooks.py +144 -0
  241. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/main.py +31 -0
  242. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/__init__.py +1 -0
  243. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/middleware/cors.py +20 -0
  244. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/__init__.py +1 -0
  245. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/shutdown/cleanup.py +14 -0
  246. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/__init__.py +1 -0
  247. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/component_health.py.jinja +418 -0
  248. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/backend/startup/database_init.py.jinja +83 -0
  249. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/__init__.py +5 -0
  250. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/__init__.py +27 -0
  251. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/table.py +78 -0
  252. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/controls/text.py +142 -0
  253. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/__init__.py.jinja +47 -0
  254. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/ai_card.py +287 -0
  255. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/auth_card.py +198 -0
  256. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/base_card.py +256 -0
  257. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_factory.py +227 -0
  258. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/card_utils.py +333 -0
  259. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/database_card.py +420 -0
  260. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/fastapi_card.py +328 -0
  261. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/flet_card.py +267 -0
  262. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/redis_card.py +322 -0
  263. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/scheduler_card.py +352 -0
  264. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/services_card.py +233 -0
  265. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/dashboard/cards/worker_card.py +684 -0
  266. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/main.py.jinja +653 -0
  267. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/frontend/theme.py +48 -0
  268. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/__init__.py +1 -0
  269. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/scheduler/main.py.jinja +156 -0
  270. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/CLAUDE.md.jinja +213 -0
  271. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/__init__.py +6 -0
  272. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/constants.py.jinja +30 -0
  273. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/pools.py +97 -0
  274. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/__init__.py +1 -0
  275. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/load_test.py +55 -0
  276. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/media.py +49 -0
  277. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/queues/system.py +44 -0
  278. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/registry.py +139 -0
  279. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/__init__.py +120 -0
  280. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/load_tasks.py +507 -0
  281. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/simple_system_tasks.py +33 -0
  282. aegis/templates/copier-aegis-project/{{ project_slug }}/app/components/worker/tasks/system_tasks.py +281 -0
  283. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/config.py.jinja +178 -0
  284. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/constants.py +58 -0
  285. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/db.py.jinja +176 -0
  286. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/log.py +92 -0
  287. aegis/templates/copier-aegis-project/{{ project_slug }}/app/core/security.py +62 -0
  288. aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/__init__.py +1 -0
  289. aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/scheduler.py.jinja +21 -0
  290. aegis/templates/copier-aegis-project/{{ project_slug }}/app/entrypoints/webserver.py +39 -0
  291. aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/__init__.py +0 -0
  292. aegis/templates/copier-aegis-project/{{ project_slug }}/app/integrations/main.py +61 -0
  293. aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/__init__.py +1 -0
  294. aegis/templates/copier-aegis-project/{{ project_slug }}/app/models/user.py +44 -0
  295. aegis/templates/copier-aegis-project/{{ project_slug }}/app/py.typed +0 -0
  296. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/__init__.py +1 -0
  297. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/__init__.py +8 -0
  298. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/config.py +130 -0
  299. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/conversation.py +213 -0
  300. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/health.py +96 -0
  301. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/models.py +229 -0
  302. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/providers.py.jinja +370 -0
  303. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/ai/service.py +387 -0
  304. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/__init__.py +1 -0
  305. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/auth_service.py +40 -0
  306. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/health.py +162 -0
  307. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/auth/user_service.py +82 -0
  308. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/middleware_inspector.py.jinja +223 -0
  309. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/models.py.jinja +70 -0
  310. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/backend/route_inspector.py.jinja +155 -0
  311. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test.py +678 -0
  312. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/load_test_models.py +265 -0
  313. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/__init__.py.jinja +21 -0
  314. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/models.py.jinja +119 -0
  315. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/scheduled_task_manager.py.jinja +273 -0
  316. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/scheduler/task_monitor.py.jinja +189 -0
  317. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/__init__.py +15 -0
  318. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/shared/models.py +26 -0
  319. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/__init__.py +52 -0
  320. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/alerts.py +94 -0
  321. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/backup.py.jinja +119 -0
  322. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/health.py.jinja +1333 -0
  323. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/models.py +243 -0
  324. aegis/templates/copier-aegis-project/{{ project_slug }}/app/services/system/ui.py +52 -0
  325. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57223!aegis-manifesto.png +0 -0
  326. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57224!aegis-manifesto-dark.png +0 -0
  327. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57225!aegis-manifesto-square-backup.png +0 -0
  328. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57533!aegis-manifesto.png +0 -0
  329. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57534!aegis-manifesto-dark.png +0 -0
  330. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57538!aegis-manifesto-square-backup.png +0 -0
  331. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57897!aegis-manifesto.png +0 -0
  332. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57898!aegis-manifesto-dark.png +0 -0
  333. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!57904!aegis-manifesto-square-backup.png +0 -0
  334. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58315!aegis-manifesto.png +0 -0
  335. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58316!aegis-manifesto-dark.png +0 -0
  336. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58324!aegis-manifesto-square-backup.png +0 -0
  337. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58837!aegis-manifesto.png +0 -0
  338. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58838!aegis-manifesto-dark.png +0 -0
  339. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/.!58849!aegis-manifesto-square-backup.png +0 -0
  340. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-dark.png +0 -0
  341. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto-square-backup.png +0 -0
  342. aegis/templates/copier-aegis-project/{{ project_slug }}/assets/aegis-manifesto.png +0 -0
  343. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/.env.example.jinja +64 -0
  344. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/README.md.jinja +172 -0
  345. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/docker-compose.yml.jinja +78 -0
  346. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/mkdocs.yml.jinja +62 -0
  347. aegis/templates/copier-aegis-project/{{ project_slug }}/clean-validation/pyproject.toml.jinja +120 -0
  348. aegis/templates/copier-aegis-project/{{ project_slug }}/docker-compose.yml.jinja +200 -0
  349. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/api.md.jinja +191 -0
  350. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md +0 -0
  351. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/components/scheduler.md.jinja +621 -0
  352. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/development.md.jinja +215 -0
  353. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/health.md.jinja +240 -0
  354. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/javascripts/mermaid-config.js +62 -0
  355. aegis/templates/copier-aegis-project/{{ project_slug }}/docs/stylesheets/mermaid.css +95 -0
  356. aegis/templates/copier-aegis-project/{{ project_slug }}/mkdocs.yml.jinja +62 -0
  357. aegis/templates/copier-aegis-project/{{ project_slug }}/pyproject.toml.jinja +131 -0
  358. aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh +87 -0
  359. aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/entrypoint.sh.jinja +93 -0
  360. aegis/templates/copier-aegis-project/{{ project_slug }}/scripts/gen_docs.py +16 -0
  361. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/__init__.py +1 -0
  362. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_auth_endpoints.py.jinja +307 -0
  363. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_health_endpoints.py.jinja +262 -0
  364. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_scheduler_endpoints.py.jinja +214 -0
  365. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/api/test_worker_endpoints.py.jinja +165 -0
  366. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_ai_rendering.py +427 -0
  367. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/cli/test_conversation_memory.py +465 -0
  368. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/components/test_scheduler.py +43 -0
  369. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/conftest.py.jinja +195 -0
  370. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/__init__.py +1 -0
  371. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/__init__.py +1 -0
  372. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/conftest.py +78 -0
  373. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_health.py +157 -0
  374. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_models.py +164 -0
  375. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/ai/test_service.py +198 -0
  376. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_auth_integration.py.jinja +528 -0
  377. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_component_integration.py.jinja +387 -0
  378. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_conversation_persistence.py +342 -0
  379. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_health_logic.py.jinja +663 -0
  380. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_models.py +619 -0
  381. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_load_test_service.py +603 -0
  382. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_middleware_inspector.py.jinja +248 -0
  383. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_scheduled_task_manager.py.jinja +292 -0
  384. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_system_service.py +98 -0
  385. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/services/test_worker_health_registration.py.jinja +257 -0
  386. aegis/templates/copier-aegis-project/{{ project_slug }}/tests/test_core.py +49 -0
  387. aegis/templates/copier-aegis-project/{{ project_slug }}/uv.lock +1673 -0
  388. aegis_stack-0.2.0rc2.dist-info/METADATA +165 -0
  389. aegis_stack-0.2.0rc2.dist-info/RECORD +392 -0
  390. aegis_stack-0.2.0rc2.dist-info/WHEEL +4 -0
  391. aegis_stack-0.2.0rc2.dist-info/entry_points.txt +3 -0
  392. aegis_stack-0.2.0rc2.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,48 @@
1
+ """Simple theme management for the dashboard."""
2
+
3
+ import flet as ft
4
+
5
+
6
+ class ThemeManager:
7
+ """Manages light/dark theme switching for the Flet page."""
8
+
9
+ def __init__(self, page: ft.Page) -> None:
10
+ self.page = page
11
+ self.is_dark_mode = True # Default to dark
12
+
13
+ async def initialize_themes(self) -> None:
14
+ """Initialize theme system with dark mode as default."""
15
+ self.page.theme_mode = ft.ThemeMode.DARK
16
+ self.is_dark_mode = True
17
+ self.page.update()
18
+
19
+ async def toggle_theme(self) -> None:
20
+ """Toggle between light and dark themes."""
21
+ if self.is_dark_mode:
22
+ self.page.theme_mode = ft.ThemeMode.LIGHT
23
+ self.is_dark_mode = False
24
+ else:
25
+ self.page.theme_mode = ft.ThemeMode.DARK
26
+ self.is_dark_mode = True
27
+
28
+ self.page.update()
29
+
30
+ def get_status_colors(self, is_healthy: bool) -> tuple[str, str, str]:
31
+ """Get (background, text, border) colors for status indicators."""
32
+ if is_healthy:
33
+ if self.is_dark_mode:
34
+ return (ft.Colors.GREEN_900, ft.Colors.GREEN_100, ft.Colors.GREEN)
35
+ else:
36
+ return (ft.Colors.GREEN_100, ft.Colors.GREEN_800, ft.Colors.GREEN)
37
+ else:
38
+ if self.is_dark_mode:
39
+ return (ft.Colors.RED_900, ft.Colors.RED_100, ft.Colors.ERROR)
40
+ else:
41
+ return (ft.Colors.RED_100, ft.Colors.RED_800, ft.Colors.ERROR)
42
+
43
+ def get_info_colors(self) -> tuple[str, str, str]:
44
+ """Get (background, text, border) colors for info cards."""
45
+ if self.is_dark_mode:
46
+ return (ft.Colors.BLUE_900, ft.Colors.BLUE_100, ft.Colors.PRIMARY)
47
+ else:
48
+ return (ft.Colors.BLUE_100, ft.Colors.BLUE_800, ft.Colors.PRIMARY)
@@ -0,0 +1,156 @@
1
+ """
2
+ Scheduler component for {{ cookiecutter.project_name }}.
3
+
4
+ Simple, explicit job scheduling - just import functions and schedule them.
5
+ Add your own jobs by importing service functions and calling scheduler.add_job().
6
+ """
7
+
8
+ import asyncio
9
+ import os
10
+
11
+ from apscheduler.schedulers.asyncio import AsyncIOScheduler
12
+ {% if cookiecutter.scheduler_backend != "memory" %}
13
+ from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
14
+ from app.core.db import engine, init_database, db_session
15
+ from app.services.scheduler.models import APSchedulerJob
16
+ from app.services.system.backup import backup_database_job
17
+ {% elif cookiecutter.include_scheduler == "yes" and cookiecutter.include_database == "yes" %}
18
+ from app.services.system.backup import backup_database_job
19
+ {% endif %}
20
+
21
+ from app.core.log import logger
22
+
23
+ {% if cookiecutter.scheduler_backend != "memory" %}
24
+
25
+ def _job_exists_in_database(job_id: str) -> bool:
26
+ """Check if a job already exists in the persistence database using SQLModel."""
27
+ try:
28
+ from sqlmodel import select
29
+
30
+ with db_session() as session:
31
+ # Query for job by ID using modern SQLModel pattern
32
+ query = select(APSchedulerJob).where(APSchedulerJob.id == job_id)
33
+ result = session.exec(query)
34
+ job = result.first()
35
+ return job is not None
36
+ except Exception as e:
37
+ logger.warning(f"Could not check for existing job {job_id}: {e}")
38
+ # If we can't check, assume it doesn't exist (safer to add than skip)
39
+ return False
40
+
41
+ {% endif %}
42
+
43
+
44
+
45
+
46
+ def create_scheduler() -> AsyncIOScheduler:
47
+ """Create and configure the scheduler with all jobs."""
48
+ {% if cookiecutter.scheduler_backend != "memory" %}
49
+ # Ensure database is initialized before creating jobstore
50
+ init_database()
51
+
52
+ # Configure SQLAlchemy jobstore for persistence
53
+ jobstore = SQLAlchemyJobStore(engine=engine, tablename='apscheduler_jobs')
54
+ jobstores = {'default': jobstore}
55
+ scheduler = AsyncIOScheduler(jobstores=jobstores)
56
+ logger.info("📊 Scheduler using SQLite database for job persistence")
57
+ {% else %}
58
+ # Use in-memory jobstore (default)
59
+ scheduler = AsyncIOScheduler()
60
+ logger.info(
61
+ "🕒 Scheduler running in memory mode (jobs won't persist across restarts)"
62
+ )
63
+ {% endif %}
64
+
65
+ # ============================================================================
66
+ # JOB SCHEDULE CONFIGURATION
67
+ #
68
+ # PERSISTENCE BEHAVIOR:
69
+ # - Jobs are checked against the database first
70
+ # - Existing jobs are preserved (respects runtime modifications)
71
+ # - New jobs are added from code configuration
72
+ # - Set SCHEDULER_FORCE_UPDATE=true to override all jobs from code
73
+ #
74
+ # To update schedules during deployment:
75
+ # SCHEDULER_FORCE_UPDATE=true docker-compose up -d scheduler
76
+ # ============================================================================
77
+
78
+ {% if cookiecutter.scheduler_backend != "memory" or (cookiecutter.include_scheduler == "yes" and cookiecutter.include_database == "yes") %}
79
+ # Check environment flag for force updates (useful during deployments)
80
+ force_update = os.getenv("SCHEDULER_FORCE_UPDATE", "false").lower() == "true"
81
+ # Database backup job (runs daily at 2 AM when database is available)
82
+ job_id = "database_backup"
83
+ {% if cookiecutter.scheduler_backend != "memory" %}
84
+ # For persistent schedulers, check database directly since
85
+ # scheduler hasn't loaded jobs yet
86
+ job_exists = _job_exists_in_database(job_id)
87
+ {% else %}
88
+ # For memory schedulers, scheduler.get_job() works fine
89
+ existing_job = scheduler.get_job(job_id)
90
+ job_exists = existing_job is not None
91
+ {% endif %}
92
+
93
+ if not job_exists or force_update:
94
+ if job_exists and force_update:
95
+ logger.info(f"🔄 Force updating job '{job_id}' from code configuration")
96
+ else:
97
+ logger.info(f"➕ Adding new job '{job_id}'")
98
+
99
+ scheduler.add_job(
100
+ backup_database_job,
101
+ trigger="cron",
102
+ hour=2,
103
+ minute=0,
104
+ id=job_id,
105
+ name="Daily Database Backup",
106
+ max_instances=1,
107
+ coalesce=True,
108
+ replace_existing=True # Safe to use since we check first
109
+ )
110
+ else:
111
+ {% if cookiecutter.scheduler_backend != "memory" %}
112
+ msg = f"✅ Job '{job_id}' exists in database, preserving current configuration"
113
+ logger.info(msg)
114
+ {% else %}
115
+ logger.info(
116
+ f"✅ Job '{job_id}' exists, preserving current configuration: "
117
+ f"{existing_job.trigger}"
118
+ )
119
+ {% endif %}
120
+ {% endif %}
121
+
122
+ # Add your own scheduled jobs here by importing service functions
123
+ # and calling scheduler.add_job() with your custom business logic
124
+
125
+ return scheduler
126
+
127
+
128
+ async def run_scheduler() -> None:
129
+ """Main scheduler runner with lifecycle management."""
130
+
131
+ logger.info("🕒 Starting {{ cookiecutter.project_name }} Scheduler")
132
+
133
+ scheduler = create_scheduler()
134
+
135
+ try:
136
+ scheduler.start()
137
+ logger.info("✅ Scheduler started successfully")
138
+ logger.info(f"📋 {len(scheduler.get_jobs())} jobs scheduled:")
139
+
140
+ for job in scheduler.get_jobs():
141
+ logger.info(f" • {job.name} - {job.trigger}")
142
+
143
+
144
+ # Keep the scheduler running
145
+ while True:
146
+ await asyncio.sleep(1)
147
+
148
+ except KeyboardInterrupt:
149
+ logger.info("🛑 Received shutdown signal")
150
+ except Exception as e:
151
+ logger.error(f"❌ Scheduler error: {e}")
152
+ raise
153
+ finally:
154
+ if scheduler.running:
155
+ scheduler.shutdown()
156
+ logger.info("✅ Scheduler stopped gracefully")
@@ -0,0 +1,213 @@
1
+ # Worker Component Development Guide
2
+
3
+ This guide covers arq worker architecture patterns and development for the Aegis Stack worker component.
4
+
5
+ ## Worker Architecture (arq)
6
+
7
+ Aegis Stack uses pure **arq patterns** without custom wrappers, following native arq CLI and configuration patterns.
8
+
9
+ ### Worker Configuration Structure
10
+
11
+ Each worker queue has its own `WorkerSettings` class:
12
+ - `app/components/worker/queues/system.py` - System maintenance worker
13
+ - `app/components/worker/queues/load_test.py` - Load testing worker
14
+ - `app/components/worker/queues/media.py` - Media processing worker
15
+
16
+ ### Worker Services in Docker
17
+
18
+ Workers run as separate Docker services with specific names:
19
+ - **`worker-system`** - System maintenance tasks (low concurrency, high reliability)
20
+ - **`worker-load-test`** - High-concurrency load testing (up to 50 concurrent jobs)
21
+ - **`worker-media`** - File/media processing (commented out by default)
22
+
23
+ ## Adding Worker Tasks
24
+
25
+ ### 1. Create Task Functions
26
+ Tasks are pure async functions in `app/components/worker/tasks/`:
27
+ ```python
28
+ # app/components/worker/tasks/my_tasks.py
29
+ async def my_background_task() -> dict[str, str]:
30
+ """My custom background task."""
31
+ logger.info("Running my background task")
32
+
33
+ # Your task logic here
34
+ await asyncio.sleep(1) # Simulate work
35
+
36
+ return {
37
+ "status": "completed",
38
+ "timestamp": datetime.now(UTC).isoformat(),
39
+ "task": "my_background_task"
40
+ }
41
+ ```
42
+
43
+ ### 2. Register with Worker Queue
44
+ Import and add to the appropriate `WorkerSettings`:
45
+ ```python
46
+ # app/components/worker/queues/system.py
47
+ from app.components.worker.tasks.my_tasks import my_background_task
48
+
49
+ class WorkerSettings:
50
+ functions = [
51
+ system_health_check,
52
+ cleanup_temp_files,
53
+ my_background_task, # Add your task here
54
+ ]
55
+
56
+ # Standard arq configuration
57
+ redis_settings = RedisSettings.from_dsn(settings.REDIS_URL)
58
+ queue_name = "arq:queue:system"
59
+ max_jobs = 15
60
+ job_timeout = 300
61
+ ```
62
+
63
+ ## Native arq CLI Usage
64
+
65
+ ### Worker Health Checks
66
+ ```bash
67
+ # Check if workers can connect to Redis and validate configuration
68
+ uv run python -m arq app.components.worker.queues.system.WorkerSettings --check
69
+ uv run python -m arq app.components.worker.queues.load_test.WorkerSettings --check
70
+ uv run python -m arq app.components.worker.queues.media.WorkerSettings --check
71
+ ```
72
+
73
+ ### Local Worker Development
74
+ ```bash
75
+ # Run worker locally with auto-reload for development
76
+ uv run python -m arq app.components.worker.queues.system.WorkerSettings --watch app/
77
+
78
+ # Run worker in burst mode (process all jobs and exit)
79
+ uv run python -m arq app.components.worker.queues.system.WorkerSettings --burst
80
+ ```
81
+
82
+ ### Worker Configuration in Health Checks
83
+
84
+ The health system reads worker configuration from `app/core/config.py` but workers themselves use their own `WorkerSettings` classes:
85
+
86
+ ```python
87
+ # Health system reads this for monitoring
88
+ WORKER_QUEUES: dict[str, dict[str, Any]] = {
89
+ "system": {
90
+ "description": "System maintenance and monitoring tasks",
91
+ "max_jobs": 15,
92
+ "timeout_seconds": 300,
93
+ "queue_name": "arq:queue:system",
94
+ },
95
+ "load_test": {
96
+ "description": "Load testing and performance testing",
97
+ "max_jobs": 50,
98
+ "timeout_seconds": 60,
99
+ "queue_name": "arq:queue:load_test",
100
+ }
101
+ }
102
+
103
+ # But workers use their own WorkerSettings classes for actual configuration
104
+ ```
105
+
106
+ ## Key Differences from Custom Worker Systems
107
+
108
+ ### ✅ What We Do (Pure arq):
109
+ - Use native arq CLI: `python -m arq WorkerSettings`
110
+ - Standard `WorkerSettings` classes with `functions` list
111
+ - Direct task imports into worker configurations
112
+ - Native arq health checking and monitoring
113
+
114
+ ### ❌ What We Don't Do (Avoided custom patterns):
115
+ - Custom worker wrapper classes
116
+ - Central worker registry systems
117
+ - Custom CLI commands for workers
118
+ - Configuration-driven task discovery
119
+
120
+ This approach keeps workers transparent and lets developers use arq exactly as documented in the official arq documentation.
121
+
122
+ ## Docker Worker Debugging Commands
123
+
124
+ ### View Worker Logs
125
+ ```bash
126
+ # View specific worker logs
127
+ docker compose logs worker-system # System worker logs
128
+ docker compose logs worker-load-test # Load test worker logs
129
+ docker compose logs -f worker-system # Follow system worker in real-time
130
+ docker compose logs -f worker-load-test # Follow load test worker in real-time
131
+
132
+ # View all workers at once
133
+ docker compose logs -f worker-system worker-load-test
134
+
135
+ # Filter for errors in specific workers
136
+ docker compose logs worker-load-test | grep "ERROR\|failed\|TypeError"
137
+
138
+ # Monitor worker processes and resources
139
+ docker compose exec worker-system ps aux # Check system worker processes
140
+ docker compose exec worker-load-test ps aux # Check load test worker processes
141
+ docker stats worker-system worker-load-test # Monitor resource usage
142
+ docker compose restart worker-system # Restart specific worker
143
+ ```
144
+
145
+ ### Essential Docker Log Monitoring
146
+
147
+ **Check Worker Logs for Load Test Issues:**
148
+ ```bash
149
+ # View real-time worker logs
150
+ docker compose logs -f worker
151
+
152
+ # Check specific container logs
153
+ docker logs <container-id>
154
+
155
+ # View logs with timestamps
156
+ docker compose logs --timestamps worker
157
+
158
+ # Search logs for specific errors
159
+ docker compose logs worker | grep "TypeError\|failed"
160
+
161
+ # Check all service logs
162
+ docker compose logs -f
163
+ ```
164
+
165
+ **Load Test Debugging Workflow:**
166
+ 1. **Run Load Test**: `uv run {{ cookiecutter.project_slug }} load-test run --type io_simulation --tasks 10`
167
+ 2. **Monitor Worker Logs**: `docker compose logs -f worker-load-test` (in separate terminal)
168
+ 3. **Look for**:
169
+ - `TypeError` messages indicating parameter mismatches
170
+ - Task completion vs failure counts (`j_complete=X j_failed=Y`)
171
+ - Task execution times and errors
172
+ - Redis connection issues
173
+
174
+ **Common Error Patterns:**
175
+ - `TypeError: function() got an unexpected keyword argument 'param'` - Parameter mismatch between orchestrator and task function
176
+ - `j_failed=X` increasing rapidly - Worker tasks failing due to code issues
177
+ - `Redis connection failed` - Infrastructure connectivity problems
178
+ - `delayed=X.XXs` - Queue saturation or worker overload
179
+
180
+ **System Health Verification:**
181
+ ```bash
182
+ # Check all containers
183
+ docker compose ps
184
+
185
+ # Check system health via API
186
+ uv run {{ cookiecutter.project_slug }} health status --detailed
187
+
188
+ # Monitor Redis connection
189
+ docker compose logs redis
190
+ ```
191
+
192
+ ## Worker Development Best Practices
193
+
194
+ ### Task Design Patterns
195
+ 1. **Pure Functions** - Tasks should be self-contained with minimal dependencies
196
+ 2. **Error Handling** - Always include try/catch with proper logging
197
+ 3. **Return Values** - Return structured data for monitoring and debugging
198
+ 4. **Timeouts** - Set appropriate timeouts for different task types
199
+ 5. **Retry Logic** - Use arq's built-in retry mechanisms
200
+
201
+ ### Queue Management
202
+ 1. **Separate Concerns** - Use different queues for different types of work
203
+ 2. **Concurrency Limits** - Set appropriate max_jobs for each queue type
204
+ 3. **Priority Queues** - Use different queues for different priorities
205
+ 4. **Dead Letter Queues** - Monitor failed jobs and implement recovery
206
+
207
+ ### Monitoring and Observability
208
+ 1. **Structured Logging** - Use structured logs for easy parsing
209
+ 2. **Metrics Collection** - Track task execution times and success rates
210
+ 3. **Health Checks** - Implement health checks for worker availability
211
+ 4. **Alerting** - Set up alerts for queue depth and failure rates
212
+
213
+ This approach ensures workers are maintainable, debuggable, and follow established patterns.
@@ -0,0 +1,6 @@
1
+ """
2
+ Worker component for background task processing.
3
+
4
+ This component handles asynchronous background tasks using arq (Redis-based queues).
5
+ Tasks are organized into priority queues (high, medium, low) and by functional area.
6
+ """
@@ -0,0 +1,30 @@
1
+ """
2
+ Worker component constants.
3
+
4
+ This module contains constants specific to the worker component,
5
+ keeping them separate from global application constants.
6
+ """
7
+
8
+ from enum import Enum
9
+
10
+
11
+ class TaskNames:
12
+ """Worker task function names - must match actual function names in code."""
13
+
14
+ # Orchestrator
15
+ LOAD_TEST_ORCHESTRATOR = "load_test_orchestrator"
16
+
17
+ # Load test tasks
18
+ CPU_INTENSIVE_TASK = "cpu_intensive_task"
19
+ IO_SIMULATION_TASK = "io_simulation_task"
20
+ MEMORY_OPERATIONS_TASK = "memory_operations_task"
21
+ FAILURE_TESTING_TASK = "failure_testing_task"
22
+
23
+
24
+ class LoadTestTypes(Enum):
25
+ """Load test type identifiers for task selection."""
26
+
27
+ CPU_INTENSIVE = "cpu_intensive"
28
+ IO_SIMULATION = "io_simulation"
29
+ MEMORY_OPERATIONS = "memory_operations"
30
+ FAILURE_TESTING = "failure_testing"
@@ -0,0 +1,97 @@
1
+ """
2
+ Worker pool management for client-side task enqueueing.
3
+
4
+ This module provides Redis connection pooling and caching for enqueueing tasks
5
+ to worker queues. Separated from worker management to allow clean architectural
6
+ separation between client-side enqueueing and worker-side processing.
7
+ """
8
+
9
+ from app.core.config import get_default_queue, settings
10
+ from app.core.log import logger
11
+ from arq import create_pool
12
+ from arq.connections import ArqRedis, RedisSettings
13
+
14
+ # Global pool cache to avoid creating new Redis connections repeatedly
15
+ _pool_cache: dict[str, ArqRedis] = {}
16
+
17
+
18
+ async def get_queue_pool(queue_type: str | None = None) -> tuple[ArqRedis, str]:
19
+ """
20
+ Get Redis pool for enqueuing tasks to specific functional queue.
21
+
22
+ Uses connection pooling to avoid creating new Redis connections repeatedly.
23
+
24
+ Args:
25
+ queue_type: Functional queue type (defaults to configured default queue)
26
+
27
+ Returns:
28
+ Tuple of (pool, queue_name) for enqueueing tasks
29
+ """
30
+ # Use configured default queue if not specified
31
+ if queue_type is None:
32
+ queue_type = get_default_queue()
33
+
34
+ from app.core.config import get_available_queues, is_valid_queue
35
+
36
+ if not is_valid_queue(queue_type):
37
+ available = get_available_queues()
38
+ raise ValueError(f"Invalid queue type '{queue_type}'. Available: {available}")
39
+
40
+ from app.components.worker.registry import get_queue_metadata
41
+
42
+ queue_name = get_queue_metadata(queue_type)["queue_name"]
43
+
44
+ # Check cache first to avoid creating new Redis connections
45
+ redis_url = (
46
+ settings.redis_url_effective
47
+ if hasattr(settings, "redis_url_effective")
48
+ else settings.REDIS_URL
49
+ )
50
+ cache_key = f"{queue_type}_{redis_url}"
51
+
52
+ if cache_key in _pool_cache:
53
+ # Reuse existing pool
54
+ cached_pool = _pool_cache[cache_key]
55
+ try:
56
+ # Test if pool is still valid by doing a quick ping
57
+ await cached_pool.ping()
58
+ return cached_pool, queue_name
59
+ except Exception:
60
+ # Pool is stale, remove from cache and create new one
61
+ logger.debug(f"Removing stale pool from cache: {cache_key}")
62
+ del _pool_cache[cache_key]
63
+
64
+ # Create new Redis pool and cache it with improved connection settings
65
+ redis_url = (
66
+ settings.redis_url_effective
67
+ if hasattr(settings, "redis_url_effective")
68
+ else settings.REDIS_URL
69
+ )
70
+ base_settings = RedisSettings.from_dsn(redis_url)
71
+ redis_settings = RedisSettings(
72
+ host=base_settings.host,
73
+ port=base_settings.port,
74
+ database=base_settings.database,
75
+ password=base_settings.password,
76
+ conn_timeout=settings.REDIS_CONN_TIMEOUT,
77
+ conn_retries=settings.REDIS_CONN_RETRIES,
78
+ conn_retry_delay=settings.REDIS_CONN_RETRY_DELAY,
79
+ )
80
+ pool = await create_pool(redis_settings)
81
+ _pool_cache[cache_key] = pool
82
+
83
+ logger.debug(f"Created and cached new Redis pool: {cache_key}")
84
+ return pool, queue_name
85
+
86
+
87
+ async def clear_pool_cache() -> None:
88
+ """Clear all cached pools. Use during shutdown or for testing."""
89
+ for cache_key, pool in _pool_cache.items():
90
+ try:
91
+ await pool.aclose()
92
+ logger.debug(f"Closed cached pool: {cache_key}")
93
+ except Exception as e:
94
+ logger.warning(f"Error closing cached pool {cache_key}: {e}")
95
+
96
+ _pool_cache.clear()
97
+ logger.info("Pool cache cleared")
@@ -0,0 +1 @@
1
+ """Worker queue configurations using native arq WorkerSettings."""
@@ -0,0 +1,55 @@
1
+ """
2
+ Load test worker queue configuration.
3
+
4
+ Handles load testing orchestration and synthetic workload tasks using native arq
5
+ patterns.
6
+ """
7
+
8
+ # Import load test tasks
9
+ from app.components.worker.tasks.load_tasks import (
10
+ cpu_intensive_task,
11
+ failure_testing_task,
12
+ io_simulation_task,
13
+ memory_operations_task,
14
+ )
15
+ from app.components.worker.tasks.system_tasks import (
16
+ load_test_orchestrator,
17
+ )
18
+ from app.core.config import settings
19
+ from arq.connections import RedisSettings
20
+
21
+
22
+ class WorkerSettings:
23
+ """Load testing worker configuration."""
24
+
25
+ # Human-readable description
26
+ description = "Load testing and performance testing"
27
+
28
+ # Task functions for this queue
29
+ functions = [
30
+ # Load test orchestrator
31
+ load_test_orchestrator,
32
+ # Synthetic workload tasks
33
+ cpu_intensive_task,
34
+ io_simulation_task,
35
+ memory_operations_task,
36
+ failure_testing_task,
37
+ ]
38
+
39
+ # arq configuration with improved connection settings
40
+ base_settings = RedisSettings.from_dsn(settings.REDIS_URL)
41
+ redis_settings = RedisSettings(
42
+ host=base_settings.host,
43
+ port=base_settings.port,
44
+ database=base_settings.database,
45
+ password=base_settings.password,
46
+ conn_timeout=settings.REDIS_CONN_TIMEOUT,
47
+ conn_retries=settings.REDIS_CONN_RETRIES,
48
+ conn_retry_delay=settings.REDIS_CONN_RETRY_DELAY,
49
+ )
50
+ queue_name = "arq:queue:load_test"
51
+ max_jobs = 50 # High concurrency for load testing
52
+ job_timeout = 60 # Quick tasks
53
+ keep_result = settings.WORKER_KEEP_RESULT_SECONDS
54
+ max_tries = settings.WORKER_MAX_TRIES
55
+ health_check_interval = settings.WORKER_HEALTH_CHECK_INTERVAL
@@ -0,0 +1,49 @@
1
+ """
2
+ Media worker queue configuration.
3
+
4
+ Handles image processing, file operations, and media transformations using native
5
+ arq patterns.
6
+ """
7
+
8
+ from typing import Any
9
+
10
+ from app.core.config import settings
11
+ from arq.connections import RedisSettings
12
+
13
+ # Import media tasks (when available)
14
+ # from app.components.worker.tasks.media_tasks import (
15
+ # image_resize,
16
+ # video_encode,
17
+ # file_convert,
18
+ # )
19
+
20
+
21
+ class WorkerSettings:
22
+ """Media processing worker configuration."""
23
+
24
+ # Human-readable description
25
+ description = "Image and file processing"
26
+
27
+ # Task functions for this queue
28
+ functions: list[Any] = [
29
+ # Media processing tasks will be added here
30
+ # Example: image_resize, video_encode, file_convert
31
+ ]
32
+
33
+ # arq configuration with improved connection settings
34
+ base_settings = RedisSettings.from_dsn(settings.REDIS_URL)
35
+ redis_settings = RedisSettings(
36
+ host=base_settings.host,
37
+ port=base_settings.port,
38
+ database=base_settings.database,
39
+ password=base_settings.password,
40
+ conn_timeout=settings.REDIS_CONN_TIMEOUT,
41
+ conn_retries=settings.REDIS_CONN_RETRIES,
42
+ conn_retry_delay=settings.REDIS_CONN_RETRY_DELAY,
43
+ )
44
+ queue_name = "arq:queue:media"
45
+ max_jobs = 10 # I/O-bound file operations
46
+ job_timeout = 600 # 10 minutes - file processing can take time
47
+ keep_result = settings.WORKER_KEEP_RESULT_SECONDS
48
+ max_tries = settings.WORKER_MAX_TRIES
49
+ health_check_interval = settings.WORKER_HEALTH_CHECK_INTERVAL