minix 0.3.2__tar.gz → 0.3.4__tar.gz
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.
- {minix-0.3.2 → minix-0.3.4}/PKG-INFO +344 -7
- {minix-0.3.2 → minix-0.3.4}/README.md +337 -6
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/__init__.py +10 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/add_component_scaffold.py +36 -5
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/add_module_scaffold.py +11 -5
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/add_rag.py +6 -1
- minix-0.3.4/minix/core/cli/commands/agent_guidance.py +74 -0
- minix-0.3.4/minix/core/cli/commands/db.py +246 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/init.py +21 -3
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/init_scaffold.py +5 -2
- minix-0.3.4/minix/core/cli/commands/sync_agents.py +105 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/global_settings.py +5 -1
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/minix_settings.py +4 -0
- minix-0.3.4/minix/core/conf/project_template/.claude/skills/minix/SKILL.md +60 -0
- minix-0.3.4/minix/core/conf/project_template/.claude/skills/minix/references/cli.md +43 -0
- minix-0.3.4/minix/core/conf/project_template/.claude/skills/minix/references/concepts.md +181 -0
- minix-0.3.4/minix/core/conf/project_template/.claude/skills/minix/references/patterns.md +98 -0
- minix-0.3.4/minix/core/conf/project_template/.claude/skills/minix/references/upstream.md +71 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/AGENTS.md +124 -5
- minix-0.3.4/minix/core/conf/project_template/CLAUDE.md +5 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/entity/__init__.py +5 -0
- minix-0.3.4/minix/core/entity/pgvector_entity.py +22 -0
- minix-0.3.4/minix/core/migrations/__init__.py +21 -0
- minix-0.3.4/minix/core/migrations/env.py +102 -0
- minix-0.3.4/minix/core/migrations/scaffold.py +117 -0
- minix-0.3.4/minix/core/migrations/targets.py +48 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/__init__.py +7 -1
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/config.py +30 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/controllers/oidc_controller.py +60 -5
- minix-0.3.4/minix/core/modules/oidc/dependencies.py +238 -0
- minix-0.3.4/minix/core/modules/oidc/errors.py +14 -0
- minix-0.3.4/minix/core/modules/oidc/hooks.py +17 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/module.py +5 -5
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/services/__init__.py +1 -0
- minix-0.3.4/minix/core/modules/oidc/services/oidc_discovery_service.py +195 -0
- minix-0.3.4/minix/core/modules/oidc/services/oidc_token_client.py +147 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/services/oidc_user_service.py +27 -5
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/session.py +5 -2
- minix-0.3.4/minix/core/modules/oidc/tenant.py +68 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/controllers/rag_controller.py +32 -2
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/__init__.py +2 -0
- minix-0.3.4/minix/core/repository/pgvector/__init__.py +1 -0
- minix-0.3.4/minix/core/repository/pgvector/pgvector_repository.py +64 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/__init__.py +2 -0
- minix-0.3.4/minix/core/service/pgvector/__init__.py +1 -0
- minix-0.3.4/minix/core/service/pgvector/pgvector_service.py +37 -0
- {minix-0.3.2 → minix-0.3.4}/pyproject.toml +11 -1
- minix-0.3.2/minix/core/modules/oidc/dependencies.py +0 -137
- minix-0.3.2/minix/core/modules/oidc/services/oidc_discovery_service.py +0 -121
- {minix-0.3.2 → minix-0.3.4}/minix/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/bootstrap/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/bootstrap/bootstrap.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/cli.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/add_component.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/add_module.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/commands/init_prompts.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/cli/options.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/builders.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/env.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/.dockerignore +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/.env.example +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/.gitignore +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/Dockerfile +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/config.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/docker-compose.yml +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/entries/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/entries/api.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/entries/beat.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/conf/project_template/entries/worker.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/connector.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/object_storage_connector/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/object_storage_connector/config.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/object_storage_connector/connector.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/qdrant_connector/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/qdrant_connector/connector.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/redis_connector/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/redis_connector/redis_connector.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/sql_connector/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/sql_connector/sql_connector.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/connectors/sql_connector/transaction.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/consumer/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/consumer/async_consumer.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/controller/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/controller/controller.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/entity/entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/entity/qdrant_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/entity/redis_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/entity/sql_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/install/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/install/installable.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/model/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/model/embedding_model.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/model/mlflow_model.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/model/model.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/model/model_registry.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/module/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/module/business_module/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/module/business_module/business_module.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/module/module.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/dependencies.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/entities/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/entities/api_key_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/module.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/repositories/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/repositories/api_key_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/services/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/auth/services/api_key_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/controllers/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/entities/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/entities/oidc_user_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/repositories/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/oidc/repositories/oidc_user_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/chunking/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/chunking/preprocessor.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/chunking/smart_chunker.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/config.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/controllers/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/controllers/schemas.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/document_processor/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/document_processor/base.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/document_processor/factory.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/document_processor/gpt_processor.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/document_processor/landingai_processor.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/embeddings.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/entities/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/entities/chunk_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/entities/collection_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/entities/document_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/entities/job_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/entities/query_request_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/entities/search_request_entity.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/hybrid_retriever.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/llm_factory.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/metadata_extractor.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/module.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/prompts.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/qdrant_ops.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/rag_chain.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/refusal.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/repositories/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/repositories/chunk_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/repositories/collection_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/repositories/document_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/repositories/job_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/repositories/query_request_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/repositories/search_request_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/retrieval/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/retrieval/llm_reranker.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/retrieval/multi_query_blender.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/access_policy.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/chunk_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/collection_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/document_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/job_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/match_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/query_request_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/modules/rag/services/search_request_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/object_storage/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/object_storage/config.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/object_storage/connector.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/registry/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/registry/registry.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/qdrant/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/qdrant/qdrant_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/redis/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/redis/redis_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/sql/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/repository/sql/sql_repository.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/scheduler/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/scheduler/scheduler.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/scheduler/task/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/scheduler/task/task.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/scheduler/task/workflow_tasks.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/scheduler/workflow.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/base_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/helper_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/qdrant/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/qdrant/qdrant_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/redis/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/redis/redis_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/sql/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/service/sql/sql_service.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/utils/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/utils/mlflow/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/utils/mlflow/log_metric.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/utils/singleton/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/utils/singleton/singleton.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/utils/string/__init__.py +0 -0
- {minix-0.3.2 → minix-0.3.4}/minix/core/utils/string/to_snake_case.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: minix
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: A modular Python framework for backend, AI, and data projects
|
|
5
5
|
Author: AmirHossein Advari
|
|
6
6
|
Author-email: amiradvari@gmail.com
|
|
@@ -13,11 +13,15 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
13
13
|
Provides-Extra: ai
|
|
14
14
|
Provides-Extra: clickhouse
|
|
15
15
|
Provides-Extra: mysql
|
|
16
|
+
Provides-Extra: pgvector
|
|
16
17
|
Provides-Extra: postgresql
|
|
17
18
|
Provides-Extra: rag
|
|
18
19
|
Provides-Extra: vdb
|
|
19
20
|
Requires-Dist: Pillow (>=10.0.0) ; extra == "rag"
|
|
20
21
|
Requires-Dist: aiokafka (>=0.12.0,<0.13.0)
|
|
22
|
+
Requires-Dist: alembic (>=1.13) ; extra == "mysql"
|
|
23
|
+
Requires-Dist: alembic (>=1.13) ; extra == "postgresql"
|
|
24
|
+
Requires-Dist: alembic (>=1.13) ; extra == "rag"
|
|
21
25
|
Requires-Dist: authlib (>=1.3,<2.0)
|
|
22
26
|
Requires-Dist: boto3 (>=1.39.14,<2.0.0)
|
|
23
27
|
Requires-Dist: celery (>=5.5.3,<6.0.0)
|
|
@@ -37,6 +41,8 @@ Requires-Dist: mlflow (>=2.0) ; extra == "ai"
|
|
|
37
41
|
Requires-Dist: numpy (>=1.24) ; extra == "ai"
|
|
38
42
|
Requires-Dist: numpy (>=1.24) ; extra == "vdb"
|
|
39
43
|
Requires-Dist: pdf2image (>=1.17.0) ; extra == "rag"
|
|
44
|
+
Requires-Dist: pgvector (>=0.4) ; extra == "pgvector"
|
|
45
|
+
Requires-Dist: psycopg[binary] (>=3.1) ; extra == "pgvector"
|
|
40
46
|
Requires-Dist: psycopg[binary] (>=3.1) ; extra == "postgresql"
|
|
41
47
|
Requires-Dist: psycopg[binary] (>=3.1) ; extra == "rag"
|
|
42
48
|
Requires-Dist: pydantic-settings (>=2.0,<3.0)
|
|
@@ -78,10 +84,12 @@ Description-Content-Type: text/markdown
|
|
|
78
84
|
- [Entities](#entities)
|
|
79
85
|
- [SQL Entity](#sql-entity)
|
|
80
86
|
- [Qdrant Entity (Vector DB)](#qdrant-entity-vector-db)
|
|
87
|
+
- [PGVector Entity (PostgreSQL vectors)](#pgvector-entity-postgresql-vectors)
|
|
81
88
|
- [Redis Entity](#redis-entity)
|
|
82
89
|
- [Repositories](#repositories)
|
|
83
90
|
- [SQL Repository](#sql-repository)
|
|
84
91
|
- [Qdrant Repository](#qdrant-repository)
|
|
92
|
+
- [PGVector Repository](#pgvector-repository)
|
|
85
93
|
- [Services](#services)
|
|
86
94
|
- [Controllers](#controllers)
|
|
87
95
|
- [Connectors](#connectors)
|
|
@@ -104,6 +112,7 @@ Description-Content-Type: text/markdown
|
|
|
104
112
|
- [Embedding Model](#embedding-model)
|
|
105
113
|
- [MLflow Model (requires `ai` extra)](#mlflow-model-requires-ai-extra)
|
|
106
114
|
- [RAG Module](#rag-module)
|
|
115
|
+
- [OIDC Module](#oidc-module)
|
|
107
116
|
- [Configuration](#configuration)
|
|
108
117
|
- [Project config](#project-config)
|
|
109
118
|
- [Connectors from config](#connectors-from-config)
|
|
@@ -112,6 +121,7 @@ Description-Content-Type: text/markdown
|
|
|
112
121
|
- [SQL drivers](#sql-drivers)
|
|
113
122
|
- [AI Capabilities](#ai-capabilities)
|
|
114
123
|
- [Vector DB (Qdrant)](#vector-db-qdrant)
|
|
124
|
+
- [Vector DB (pgvector)](#vector-db-pgvector)
|
|
115
125
|
- [ClickHouse Support](#clickhouse-support)
|
|
116
126
|
- [Install All Extras](#install-all-extras)
|
|
117
127
|
- [Registry Usage](#registry-usage)
|
|
@@ -119,6 +129,13 @@ Description-Content-Type: text/markdown
|
|
|
119
129
|
- [Quick map](#quick-map)
|
|
120
130
|
- [Global options](#global-options)
|
|
121
131
|
- [`minix init`](#minix-init)
|
|
132
|
+
- [`minix db`](#minix-db)
|
|
133
|
+
- [Migration workflow](#migration-workflow)
|
|
134
|
+
- [Migration commands](#migration-commands)
|
|
135
|
+
- [Revision targets](#revision-targets)
|
|
136
|
+
- [Migration recipes](#migration-recipes)
|
|
137
|
+
- [How migrations work](#how-migrations-work)
|
|
138
|
+
- [Migration troubleshooting](#migration-troubleshooting)
|
|
122
139
|
- [`minix add module`](#minix-add-module)
|
|
123
140
|
- [SQL binding (all or none)](#sql-binding-all-or-none)
|
|
124
141
|
- [Flags](#flags)
|
|
@@ -290,6 +307,24 @@ class DocumentEntity(QdrantEntity):
|
|
|
290
307
|
return "documents"
|
|
291
308
|
```
|
|
292
309
|
|
|
310
|
+
#### PGVector Entity (PostgreSQL vectors)
|
|
311
|
+
|
|
312
|
+
Requires the `pgvector` extra and a PostgreSQL server with the `vector` extension.
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
from sqlalchemy import Text
|
|
316
|
+
from sqlalchemy.orm import Mapped, mapped_column
|
|
317
|
+
from minix.core.entity import PGVectorEntity
|
|
318
|
+
|
|
319
|
+
class DocumentEmbeddingEntity(PGVectorEntity):
|
|
320
|
+
vector_size = 1536
|
|
321
|
+
|
|
322
|
+
content: Mapped[str] = mapped_column(Text, nullable=False)
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
PGVector entities are SQL entities: they include `id`, `created_at` and
|
|
326
|
+
`updated_at`, plus a `vector` column of type `VECTOR(vector_size)`.
|
|
327
|
+
|
|
293
328
|
#### Redis Entity
|
|
294
329
|
|
|
295
330
|
```python
|
|
@@ -360,6 +395,27 @@ class DocumentRepository(QdrantRepository[DocumentEntity]):
|
|
|
360
395
|
- `query(entity, top_k)` - Similarity search
|
|
361
396
|
- `delete(entity_ids)` - Delete vectors
|
|
362
397
|
|
|
398
|
+
#### PGVector Repository
|
|
399
|
+
|
|
400
|
+
```python
|
|
401
|
+
from minix.core.repository import PGVectorRepository
|
|
402
|
+
|
|
403
|
+
class DocumentEmbeddingRepository(PGVectorRepository[DocumentEmbeddingEntity]):
|
|
404
|
+
def get_distance(self) -> str:
|
|
405
|
+
return 'Cosine' # or 'Euclid', 'Dot', 'Manhattan'
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
It extends `SqlRepository` (all SQL methods above, `sql_transaction()`
|
|
409
|
+
included) and uses the registered `SqlConnector`, which must point at PostgreSQL.
|
|
410
|
+
|
|
411
|
+
**Additional methods:**
|
|
412
|
+
- `create_extension()` - Run `CREATE EXTENSION IF NOT EXISTS vector`
|
|
413
|
+
- `search(vector, top_k, max_distance=None, **kwargs)` - Nearest neighbours, closest first; `kwargs` filter like `get_by`
|
|
414
|
+
- `search_with_distance(vector, top_k, max_distance=None, **kwargs)` - Same, as `(entity, distance)` pairs
|
|
415
|
+
|
|
416
|
+
`PGVectorService` exposes the same `search` / `search_with_distance` methods,
|
|
417
|
+
plus `get_knn(entity, top_k)`, on top of `SqlService`.
|
|
418
|
+
|
|
363
419
|
### Services
|
|
364
420
|
|
|
365
421
|
Services contain business logic:
|
|
@@ -724,7 +780,7 @@ every request when the key is set but empty): `.env` gets a random key and
|
|
|
724
780
|
Repeated `minix add rag` calls leave the generated files unchanged. Afterwards,
|
|
725
781
|
reinstall (for example `poetry lock && poetry install`), install Poppler for local
|
|
726
782
|
PDF ingestion, set the model provider's API key in `.env`, and create the SQL tables
|
|
727
|
-
|
|
783
|
+
with `minix db makemigrations -m "add rag" && minix db migrate` (see [`minix db`](#minix-db)).
|
|
728
784
|
|
|
729
785
|
**Manual registration** — in a project from `minix init` with PostgreSQL as the `default`
|
|
730
786
|
database, add the module to `installed_modules` in `config.py`:
|
|
@@ -739,8 +795,15 @@ installed_modules: list[str] = Field(
|
|
|
739
795
|
```
|
|
740
796
|
|
|
741
797
|
`bootstrap_from_settings()` (already called in `entries/api.py`) then registers
|
|
742
|
-
the connectors and installs the module. Create its tables
|
|
743
|
-
|
|
798
|
+
the connectors and installs the module. Create its tables with
|
|
799
|
+
[`minix db`](#minix-db):
|
|
800
|
+
|
|
801
|
+
```bash
|
|
802
|
+
minix db makemigrations -m "add rag"
|
|
803
|
+
minix db migrate
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
Without migrations, create them once from code instead:
|
|
744
807
|
|
|
745
808
|
```python
|
|
746
809
|
from minix.core.connectors import SqlConnector
|
|
@@ -825,6 +888,64 @@ through `provides=` on the paired repository and service.
|
|
|
825
888
|
|
|
826
889
|
---
|
|
827
890
|
|
|
891
|
+
## OIDC Module
|
|
892
|
+
|
|
893
|
+
`minix.core.modules.oidc` is a standalone OpenID Connect module (it does not depend on the core `auth` module): authorization-code login with a signed session cookie, bearer-token validation against the IdP's JWKS, role mapping, tenant resolution, a token client and a login hook. Add `OidcModule` to `INSTALLED_MODULES` and set at least `OIDC_ISSUER` and `OIDC_CLIENT_ID`.
|
|
894
|
+
|
|
895
|
+
| Setting | Default | Purpose |
|
|
896
|
+
|---|---|---|
|
|
897
|
+
| `OIDC_ISSUER` / `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` | — | IdP issuer URL (discovery) and client credentials |
|
|
898
|
+
| `OIDC_AUDIENCE` | `OIDC_CLIENT_ID` | Accepted `aud` for bearer tokens; a comma-separated list accepts several audiences. ID tokens at the login callback are always checked against `OIDC_CLIENT_ID` |
|
|
899
|
+
| `OIDC_ALGORITHMS` | `RS256,ES256,PS256` | Allowed signing algorithms; `none` and `HS*` are always rejected |
|
|
900
|
+
| `OIDC_ALLOWED_REDIRECT_HOSTS` | empty | Hosts allowed as absolute `redirect` targets on login/logout (otherwise only relative paths) |
|
|
901
|
+
| `OIDC_AUTO_CREATE_TABLE` | `true` | Create the OIDC users table once at startup |
|
|
902
|
+
| `OIDC_TENANT_CLAIM` | `organization` | Token claim holding the user's organization(s); `none` disables tenant resolution (everyone gets their personal tenant) |
|
|
903
|
+
| `OIDC_SCOPES` | `openid profile email` | Add `offline_access` to receive a refresh token. Keycloak only emits the `organization` claim when the `organization` scope is requested, e.g. `openid profile email organization` |
|
|
904
|
+
| `OIDC_ROLE_CLAIM` / `OIDC_ROLE_MAP` / `OIDC_DEFAULT_ROLE` | `realm_access.roles` / — / `user` | Role extraction and mapping |
|
|
905
|
+
| `OIDC_JWKS_TTL` | `3600` | JWKS cache seconds (an unknown `kid` triggers one refetch, at most once per 60 s) |
|
|
906
|
+
| `OIDC_SESSION_SECRET` / `OIDC_SESSION_COOKIE` / `OIDC_SESSION_TTL` / `OIDC_COOKIE_SECURE` | — / `minix_session` / `28800` / `true` | Session cookie |
|
|
907
|
+
|
|
908
|
+
**Dependencies and identity** — `get_oidc_user` and `RequireOidcRole` return an `OidcContext` (`user_id`, `email`, `role`, `claims`, `tenant_id`, `tenant_name`, `tenant_is_personal`) or raise 401/403. `resolve_oidc_context(request)` returns an `OidcContext` or `None` when the request is unauthenticated. `resolve_identity(request, fallbacks)` returns an `OidcContext`, whatever identity the first matching fallback returns, or `None`. `resolve_identity` tries a bearer from the configured issuer, then the minix session cookie, then each fallback (`async (request) -> identity | None`). A bearer from a different issuer is skipped, so the app's own JWTs reach its fallbacks; an invalid bearer from the configured issuer returns `None` without trying fallbacks. An invalid or expired minix session cookie is treated as "no session" and falls through to the fallbacks (unlike an invalid bearer from the configured issuer).
|
|
909
|
+
|
|
910
|
+
**Tenants** — the tenant comes from `OIDC_TENANT_CLAIM`, which may be a single alias string, a list of aliases, or Keycloak's map form `{alias: {"id": ...}}` (the `id` becomes `tenant_id`, the alias `tenant_name`; an entry without `id` uses its alias). With several organizations the caller picks one with the `X-Organization` header (matching id or alias). Users without an organization get a personal tenant `user:{sub}` (`tenant_is_personal=True`); organization ids starting with `user:` are ignored so they cannot collide with personal tenants. `resolve_oidc_context` and `resolve_identity` can raise `HTTPException` 400 (`organization_selection_required`) or 403 (`organization_not_in_token`) for multi-organization users: call them from FastAPI dependencies, or handle the exception. Set `OIDC_TENANT_CLAIM=none` (or `""` in `settings.py`) to disable tenant resolution: every identity gets its personal tenant and `X-Organization` is ignored.
|
|
911
|
+
|
|
912
|
+
For browser sessions, organization membership is a snapshot taken at login and stored in the session cookie: changes at the IdP apply at the next login or when the session expires (`OIDC_SESSION_TTL`, default 8 h). Session cookies issued by 0.3.3 carry no organizations and resolve as personal until the user logs in again. Very large organization claims enlarge the cookie accordingly.
|
|
913
|
+
|
|
914
|
+
**Token client** — `OidcTokenClient` (registered by `OidcModule`) wraps the token endpoint and returns `TokenSet` (`access_token`, `expires_at`, `refresh_token`, `scope`):
|
|
915
|
+
|
|
916
|
+
```python
|
|
917
|
+
from minix.core.registry import Registry
|
|
918
|
+
from minix.core.modules.oidc import OidcTokenClient
|
|
919
|
+
|
|
920
|
+
client = Registry().get(OidcTokenClient)
|
|
921
|
+
svc = client.client_credentials(audience="billing-api")
|
|
922
|
+
fresh = client.refresh(refresh_token)
|
|
923
|
+
downstream = client.exchange(subject_token=access_token, audience="other-api") # RFC 8693
|
|
924
|
+
client.revoke(refresh_token)
|
|
925
|
+
```
|
|
926
|
+
|
|
927
|
+
Errors: `OidcError` (base), `OidcTokenRevoked`, `OidcExchangeDenied`, `OidcUnavailable` (also raised for 5xx and unexpected 3xx responses).
|
|
928
|
+
|
|
929
|
+
`OidcTokenClient` is synchronous: each call blocks on an HTTP request (10 s timeout). From async code, run it in the threadpool:
|
|
930
|
+
|
|
931
|
+
```python
|
|
932
|
+
from starlette.concurrency import run_in_threadpool
|
|
933
|
+
|
|
934
|
+
tokens = await run_in_threadpool(client.exchange, access_token, "other-api")
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
**Login hook** — implement `OidcLoginHook.on_login(claims, token_response)` (sync or `async def`) and register it with `Registry().register(OidcLoginHook, instance)`. It runs once per successful login, before the session cookie is issued; an async hook is awaited. If it raises, the login fails with HTTP 500 and no session is set. minix never stores the token response: the hook owns it.
|
|
938
|
+
|
|
939
|
+
**Schema ownership** — apps that manage their schema with Alembic set `OIDC_AUTO_CREATE_TABLE=false` and include the exported table in their migrations:
|
|
940
|
+
|
|
941
|
+
```python
|
|
942
|
+
from minix.core.modules.oidc import OIDC_USERS_TABLE # SQLAlchemy Table, usable in env.py / autogenerate
|
|
943
|
+
```
|
|
944
|
+
|
|
945
|
+
**Security notes** — login/logout `redirect` accepts relative paths only (absolute URLs only for `OIDC_ALLOWED_REDIRECT_HOSTS`; userinfo and percent-encoded authority are rejected). JWT verification and the user upsert run in a threadpool; the upsert is skipped when nothing changed (300 s cache).
|
|
946
|
+
|
|
947
|
+
---
|
|
948
|
+
|
|
828
949
|
## Configuration
|
|
829
950
|
|
|
830
951
|
Minix uses a **pydantic-settings** config module (`config.py`).
|
|
@@ -940,6 +1061,12 @@ pip install "minix[ai]"
|
|
|
940
1061
|
pip install "minix[vdb]"
|
|
941
1062
|
```
|
|
942
1063
|
|
|
1064
|
+
### Vector DB (pgvector)
|
|
1065
|
+
|
|
1066
|
+
```bash
|
|
1067
|
+
pip install "minix[pgvector]"
|
|
1068
|
+
```
|
|
1069
|
+
|
|
943
1070
|
### ClickHouse Support
|
|
944
1071
|
|
|
945
1072
|
```bash
|
|
@@ -958,7 +1085,7 @@ pip install "minix[rag]"
|
|
|
958
1085
|
### Install All Extras
|
|
959
1086
|
|
|
960
1087
|
```bash
|
|
961
|
-
pip install "minix[postgresql,mysql,ai,vdb,clickhouse,rag]"
|
|
1088
|
+
pip install "minix[postgresql,pgvector,mysql,ai,vdb,clickhouse,rag]"
|
|
962
1089
|
```
|
|
963
1090
|
|
|
964
1091
|
---
|
|
@@ -1003,8 +1130,13 @@ minix add module --help
|
|
|
1003
1130
|
| New project in cwd | `minix init APP_NAME` |
|
|
1004
1131
|
| New project with RAG | `minix init APP_NAME --rag` |
|
|
1005
1132
|
| Enable built-in RAG in an existing project | `minix add rag` |
|
|
1133
|
+
| Set up migrations (once per project) | `minix db init` |
|
|
1134
|
+
| Generate a migration from entity changes | `minix db makemigrations -m "message"` |
|
|
1135
|
+
| Apply / revert migrations | `minix db migrate` / `minix db downgrade -1` |
|
|
1136
|
+
| Inspect migrations | `minix db current` / `minix db history` |
|
|
1006
1137
|
| New feature module | `minix add module MODULE_NAME` |
|
|
1007
1138
|
| Add to existing module | `minix add controller\|task\|periodic\|helper\|consumer\|binding [NAME] --module=MODULE` |
|
|
1139
|
+
| Refresh coding-agent guidance | `minix sync agents` (`--check` to verify) |
|
|
1008
1140
|
| Version | `minix -v` / `minix --version` |
|
|
1009
1141
|
|
|
1010
1142
|
### Global options
|
|
@@ -1069,8 +1201,11 @@ installs the engines you selected.
|
|
|
1069
1201
|
| `Dockerfile` | App image (`pip install "minix~=X.Y.Z"` / extras from PyPI) |
|
|
1070
1202
|
| `docker-compose.yml` | PostgreSQL or MySQL, Redis, MinIO, API, Celery; optional Qdrant / ClickHouse / MLflow |
|
|
1071
1203
|
| `.dockerignore` | Build context excludes |
|
|
1072
|
-
| `AGENTS.md` |
|
|
1204
|
+
| `AGENTS.md` | Rules for AI coding agents (CLI, decision flow, upstream-first) inside a Minix-managed block |
|
|
1205
|
+
| `CLAUDE.md` | Imports `AGENTS.md` for Claude Code; add project rules below the managed block |
|
|
1206
|
+
| `.claude/skills/minix/` | Claude Code skill: concept map, patterns, upstream workflow |
|
|
1073
1207
|
| `entries/` | `api.py`, `worker.py`, `beat.py` process entrypoints |
|
|
1208
|
+
| `migrations/<connection>/` | Alembic setup per SQL connection, driven by [`minix db`](#minix-db) |
|
|
1074
1209
|
|
|
1075
1210
|
**App wiring after init** (settings, not legacy `app_connectors.py` / `app_modules.py`):
|
|
1076
1211
|
|
|
@@ -1114,6 +1249,192 @@ pip install "minix[mysql]"
|
|
|
1114
1249
|
pip install "minix[postgresql,mysql]"
|
|
1115
1250
|
```
|
|
1116
1251
|
|
|
1252
|
+
### `minix db`
|
|
1253
|
+
|
|
1254
|
+
Database migrations for your SQL entities, built on
|
|
1255
|
+
[Alembic](https://alembic.sqlalchemy.org/). If you know Django, the commands
|
|
1256
|
+
will feel familiar: change an entity, run `makemigrations`, review the file,
|
|
1257
|
+
then run `migrate`.
|
|
1258
|
+
|
|
1259
|
+
Minix compares the database with the SQL entities of the modules in
|
|
1260
|
+
`INSTALLED_MODULES`, so you never list tables by hand. Alembic ships with the
|
|
1261
|
+
`postgresql`, `mysql` and `rag` extras.
|
|
1262
|
+
|
|
1263
|
+
#### Migration workflow
|
|
1264
|
+
|
|
1265
|
+
`minix init` already sets up migrations. For a project created another way,
|
|
1266
|
+
run `minix db init` once.
|
|
1267
|
+
|
|
1268
|
+
```bash
|
|
1269
|
+
# 1. Change an entity (or add a module with `minix add module orders`)
|
|
1270
|
+
# 2. Generate a migration; the database must be running
|
|
1271
|
+
minix db makemigrations -m "add orders"
|
|
1272
|
+
# → default: wrote migrations/default/versions/3f2a9c1b7d4e_add_orders.py
|
|
1273
|
+
|
|
1274
|
+
# 3. Read the generated file and fix anything autogenerate got wrong
|
|
1275
|
+
# 4. Apply it
|
|
1276
|
+
minix db migrate
|
|
1277
|
+
# → default: migrated to head
|
|
1278
|
+
|
|
1279
|
+
# 5. Commit the file in migrations/<connection>/versions/ with the entity change
|
|
1280
|
+
```
|
|
1281
|
+
|
|
1282
|
+
On every other machine, including CI, staging and production, only run
|
|
1283
|
+
`minix db migrate`.
|
|
1284
|
+
|
|
1285
|
+
Autogenerate is a draft, not a guarantee. Always read the file before you
|
|
1286
|
+
apply it. In particular, a renamed column or table shows up as a drop plus an
|
|
1287
|
+
add, which loses data. Change it to `op.alter_column(..., new_column_name=...)`
|
|
1288
|
+
or `op.rename_table(...)`.
|
|
1289
|
+
|
|
1290
|
+
#### Migration commands
|
|
1291
|
+
|
|
1292
|
+
These commands do more than Alembic's equivalents:
|
|
1293
|
+
|
|
1294
|
+
| Command | What it does | Options |
|
|
1295
|
+
|---------|--------------|---------|
|
|
1296
|
+
| `minix db init` | Creates `migrations/<connection>/` for each PostgreSQL / MySQL connection. Existing files are kept. | `--database/-d NAME` (repeatable; default: every PostgreSQL / MySQL connection) |
|
|
1297
|
+
| `minix db makemigrations` | Compares the entities with the live database and writes a migration. Writes nothing when there are no changes. | `-m/--message`, `--database/-d`, `--empty` (blank migration to write by hand) |
|
|
1298
|
+
| `minix db migrate [REVISION]` | Applies migrations, up to `head` by default. | `--database/-d` |
|
|
1299
|
+
| `minix db downgrade REVISION` | Reverts migrations. | `--database/-d` |
|
|
1300
|
+
|
|
1301
|
+
These run the Alembic command of the same name. Minix picks the connection and
|
|
1302
|
+
loads `config.py` and `.env`; every other argument goes to Alembic unchanged,
|
|
1303
|
+
and `minix db <command> --help` shows Alembic's own help:
|
|
1304
|
+
|
|
1305
|
+
| Command | What it does | Example |
|
|
1306
|
+
|---------|--------------|---------|
|
|
1307
|
+
| `current` | Shows the revision the database is at | `minix db current` |
|
|
1308
|
+
| `history` | Lists migrations, newest first | `minix db history -v`, `minix db history -r-3:current` (no space after `-r`) |
|
|
1309
|
+
| `heads` | Shows the latest revision(s); more than one means history has split | `minix db heads` |
|
|
1310
|
+
| `branches` | Shows where history splits | `minix db branches` |
|
|
1311
|
+
| `show` | Shows one migration | `minix db show 3f2a` |
|
|
1312
|
+
| `check` | Exits non-zero when entities have changes without a migration | `minix db check` |
|
|
1313
|
+
| `stamp` | Records a revision in the database without running anything | `minix db stamp head` |
|
|
1314
|
+
| `merge` | Writes a migration that joins two heads | `minix db merge -m "merge" heads` |
|
|
1315
|
+
| `edit` | Opens a migration in `$EDITOR` | `minix db edit head` |
|
|
1316
|
+
|
|
1317
|
+
All commands accept `--database/-d NAME` (repeatable). Without it, they run for
|
|
1318
|
+
every connection that has a `migrations/` directory, with an `== name ==`
|
|
1319
|
+
header per connection when there are several.
|
|
1320
|
+
|
|
1321
|
+
#### Revision targets
|
|
1322
|
+
|
|
1323
|
+
`migrate`, `downgrade`, `stamp` and `show` take a revision:
|
|
1324
|
+
|
|
1325
|
+
| Target | Meaning |
|
|
1326
|
+
|--------|---------|
|
|
1327
|
+
| `head` | The latest migration |
|
|
1328
|
+
| `heads` | Every head, when history has split |
|
|
1329
|
+
| `base` | Before the first migration (`downgrade base` reverts everything) |
|
|
1330
|
+
| `3f2a9c1b7d4e` or `3f2a` | A revision id, or any unique prefix of one |
|
|
1331
|
+
| `-1`, `-2` | Steps back from the current revision (`downgrade`) |
|
|
1332
|
+
| `+1`, `+2` | Steps forward from the current revision (`migrate`) |
|
|
1333
|
+
|
|
1334
|
+
#### Migration recipes
|
|
1335
|
+
|
|
1336
|
+
**Write a data migration.** Generate an empty migration and fill in
|
|
1337
|
+
`upgrade()` and `downgrade()`:
|
|
1338
|
+
|
|
1339
|
+
```bash
|
|
1340
|
+
minix db makemigrations --empty -m "backfill order status"
|
|
1341
|
+
```
|
|
1342
|
+
|
|
1343
|
+
```python
|
|
1344
|
+
def upgrade() -> None:
|
|
1345
|
+
op.execute("UPDATE orders SET status = 'NEW' WHERE status IS NULL")
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
def downgrade() -> None:
|
|
1349
|
+
pass
|
|
1350
|
+
```
|
|
1351
|
+
|
|
1352
|
+
**Catch missing migrations in CI.** With the database migrated to head, this
|
|
1353
|
+
fails when someone changed an entity without running `makemigrations`:
|
|
1354
|
+
|
|
1355
|
+
```bash
|
|
1356
|
+
minix db migrate && minix db check
|
|
1357
|
+
```
|
|
1358
|
+
|
|
1359
|
+
**Adopt migrations on a database that already has its tables.**
|
|
1360
|
+
`makemigrations` compares with the live database, so against a database that
|
|
1361
|
+
already has the tables it finds nothing to write. Generate the first migration
|
|
1362
|
+
against an empty database, then mark existing databases as up to date:
|
|
1363
|
+
|
|
1364
|
+
```bash
|
|
1365
|
+
# Against an empty local database
|
|
1366
|
+
minix db makemigrations -m "initial"
|
|
1367
|
+
minix db migrate
|
|
1368
|
+
|
|
1369
|
+
# Against each database that already has the tables (staging, production)
|
|
1370
|
+
minix db stamp head
|
|
1371
|
+
```
|
|
1372
|
+
|
|
1373
|
+
**Resolve two migrations from parallel branches.** When two branches each add a
|
|
1374
|
+
migration, `migrate` and `makemigrations` fail with a "multiple heads" error.
|
|
1375
|
+
Join them, then migrate:
|
|
1376
|
+
|
|
1377
|
+
```bash
|
|
1378
|
+
minix db heads # shows both
|
|
1379
|
+
minix db merge -m "merge" heads
|
|
1380
|
+
minix db migrate
|
|
1381
|
+
```
|
|
1382
|
+
|
|
1383
|
+
**Remove a module.** Its tables stay in the database, because Minix never drops
|
|
1384
|
+
tables that no installed module owns. To drop them, write the drop in an empty
|
|
1385
|
+
migration (`makemigrations --empty`, then `op.drop_table("orders")`).
|
|
1386
|
+
|
|
1387
|
+
**Use several databases.** Each `settings.DATABASES` connection gets its own
|
|
1388
|
+
`migrations/<connection>/` and only manages the tables of entities bound to it
|
|
1389
|
+
with `add_binding(..., connection="analytics")`:
|
|
1390
|
+
|
|
1391
|
+
```bash
|
|
1392
|
+
minix db init -d analytics
|
|
1393
|
+
minix db makemigrations -m "add events" -d analytics
|
|
1394
|
+
minix db migrate # every connection
|
|
1395
|
+
minix db migrate -d analytics # one connection
|
|
1396
|
+
```
|
|
1397
|
+
|
|
1398
|
+
**Preview the SQL instead of running it.** Use Alembic directly with `--sql`:
|
|
1399
|
+
|
|
1400
|
+
```bash
|
|
1401
|
+
alembic -c migrations/default/alembic.ini upgrade head --sql
|
|
1402
|
+
```
|
|
1403
|
+
|
|
1404
|
+
**Run in Docker.** Migrate before the new app version starts serving:
|
|
1405
|
+
|
|
1406
|
+
```bash
|
|
1407
|
+
docker compose run --rm app minix db migrate
|
|
1408
|
+
```
|
|
1409
|
+
|
|
1410
|
+
#### How migrations work
|
|
1411
|
+
|
|
1412
|
+
- `migrations/<connection>/` holds `alembic.ini`, `env.py`, `script.py.mako`
|
|
1413
|
+
and `versions/`. `env.py` calls `minix.core.migrations.run_migrations`, which
|
|
1414
|
+
loads `.env` and `config.py`, so plain `alembic -c migrations/<connection>/alembic.ini …`
|
|
1415
|
+
works on the same files.
|
|
1416
|
+
- Each connection compares only the tables of the entities bound to it. Tables
|
|
1417
|
+
that no installed module owns, including other connections' tables, are never
|
|
1418
|
+
touched.
|
|
1419
|
+
- The `default` connection records its revision in `alembic_version`; others use
|
|
1420
|
+
`alembic_version_<connection>`, so two connections can share one database.
|
|
1421
|
+
- On PostgreSQL, generated downgrades also drop the enum types of the tables
|
|
1422
|
+
they drop, so a downgrade followed by `migrate` works.
|
|
1423
|
+
- ClickHouse connections are skipped, because Alembic does not support them.
|
|
1424
|
+
|
|
1425
|
+
#### Migration troubleshooting
|
|
1426
|
+
|
|
1427
|
+
| Message | Fix |
|
|
1428
|
+
|---------|-----|
|
|
1429
|
+
| `No config.py found` | Run the command in the project root. |
|
|
1430
|
+
| `Alembic is not installed` | `pip install "minix[postgresql]"` (or `mysql`). |
|
|
1431
|
+
| `No migrations set up` / `No migrations for 'x'` | `minix db init`, or `minix db init -d x`. |
|
|
1432
|
+
| `Target database is not up to date` | `minix db migrate`, then run `makemigrations` again. |
|
|
1433
|
+
| `Multiple head revisions are present` / `Multiple heads are present` | `minix db merge -m "merge" heads`, then `minix db migrate`. |
|
|
1434
|
+
| Connection refused | Start the database (`docker compose up -d`) and check `DB_*` in `.env`. |
|
|
1435
|
+
| `type "…" already exists` on PostgreSQL | An enum type was left behind by a downgrade. Drop it in the migration (`op.execute('DROP TYPE IF EXISTS "name"')`), or by hand. |
|
|
1436
|
+
| `type "…" does not exist` after adding an enum column | Alembic creates enum types with new tables but not with new columns. Add `sa.Enum(..., name="name").create(op.get_bind(), checkfirst=True)` before `op.add_column(...)`. |
|
|
1437
|
+
|
|
1117
1438
|
### `minix add module`
|
|
1118
1439
|
|
|
1119
1440
|
Scaffold a feature module under `src/modules/<name>/`.
|
|
@@ -1211,7 +1532,7 @@ src/modules/<name>/
|
|
|
1211
1532
|
#### After scaffolding
|
|
1212
1533
|
|
|
1213
1534
|
1. Confirm `INSTALLED_MODULES` contains e.g. `"src.modules.orders.OrdersModule"`.
|
|
1214
|
-
2. Implement fields on the entity
|
|
1535
|
+
2. Implement fields on the entity, then `minix db makemigrations -m "add orders" && minix db migrate`.
|
|
1215
1536
|
3. Expand service / controller as needed.
|
|
1216
1537
|
4. Restart API / worker.
|
|
1217
1538
|
|
|
@@ -1257,6 +1578,22 @@ minix add task ShipOrder -m orders # ShipOrderTask
|
|
|
1257
1578
|
minix add binding -m payments --entity=Payment
|
|
1258
1579
|
```
|
|
1259
1580
|
|
|
1581
|
+
### Coding agents
|
|
1582
|
+
|
|
1583
|
+
`minix init` writes guidance for AI coding agents: `AGENTS.md`, `CLAUDE.md` and the
|
|
1584
|
+
Claude Code skill in `.claude/skills/minix/`. Minix owns the text between the
|
|
1585
|
+
`<!-- BEGIN MINIX -->` / `<!-- END MINIX -->` markers and the skill directory; anything
|
|
1586
|
+
you write outside the markers is kept. The guidance tells agents to build with the CLI
|
|
1587
|
+
and Minix's base classes, and to add missing generic capabilities to Minix instead of
|
|
1588
|
+
the project.
|
|
1589
|
+
|
|
1590
|
+
After upgrading Minix, refresh it so the guidance matches the installed version:
|
|
1591
|
+
|
|
1592
|
+
```bash
|
|
1593
|
+
minix sync agents # write
|
|
1594
|
+
minix sync agents --check # exit 1 if stale (for CI)
|
|
1595
|
+
```
|
|
1596
|
+
|
|
1260
1597
|
---
|
|
1261
1598
|
|
|
1262
1599
|
## License
|