aury-boot 0.0.4__py3-none-any.whl → 0.0.7__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.
- aury/boot/__init__.py +2 -2
- aury/boot/_version.py +2 -2
- aury/boot/application/__init__.py +60 -36
- aury/boot/application/adapter/__init__.py +112 -0
- aury/boot/application/adapter/base.py +511 -0
- aury/boot/application/adapter/config.py +242 -0
- aury/boot/application/adapter/decorators.py +259 -0
- aury/boot/application/adapter/exceptions.py +202 -0
- aury/boot/application/adapter/http.py +325 -0
- aury/boot/application/app/__init__.py +12 -8
- aury/boot/application/app/base.py +12 -0
- aury/boot/application/app/components.py +137 -44
- aury/boot/application/app/middlewares.py +9 -4
- aury/boot/application/app/startup.py +249 -0
- aury/boot/application/config/__init__.py +36 -1
- aury/boot/application/config/multi_instance.py +216 -0
- aury/boot/application/config/settings.py +398 -149
- aury/boot/application/constants/components.py +6 -0
- aury/boot/application/errors/handlers.py +17 -3
- aury/boot/application/middleware/logging.py +21 -120
- aury/boot/application/rpc/__init__.py +2 -2
- aury/boot/commands/__init__.py +30 -10
- aury/boot/commands/app.py +131 -1
- aury/boot/commands/docs.py +104 -17
- aury/boot/commands/generate.py +22 -22
- aury/boot/commands/init.py +68 -17
- aury/boot/commands/server/app.py +2 -3
- aury/boot/commands/templates/project/AGENTS.md.tpl +221 -0
- aury/boot/commands/templates/project/README.md.tpl +2 -2
- aury/boot/commands/templates/project/aury_docs/00-overview.md.tpl +59 -0
- aury/boot/commands/templates/project/aury_docs/01-model.md.tpl +184 -0
- aury/boot/commands/templates/project/aury_docs/02-repository.md.tpl +206 -0
- aury/boot/commands/templates/project/aury_docs/03-service.md.tpl +398 -0
- aury/boot/commands/templates/project/aury_docs/04-schema.md.tpl +95 -0
- aury/boot/commands/templates/project/aury_docs/05-api.md.tpl +116 -0
- aury/boot/commands/templates/project/aury_docs/06-exception.md.tpl +118 -0
- aury/boot/commands/templates/project/aury_docs/07-cache.md.tpl +122 -0
- aury/boot/commands/templates/project/aury_docs/08-scheduler.md.tpl +32 -0
- aury/boot/commands/templates/project/aury_docs/09-tasks.md.tpl +38 -0
- aury/boot/commands/templates/project/aury_docs/10-storage.md.tpl +115 -0
- aury/boot/commands/templates/project/aury_docs/11-logging.md.tpl +131 -0
- aury/boot/commands/templates/project/aury_docs/12-admin.md.tpl +56 -0
- aury/boot/commands/templates/project/aury_docs/13-channel.md.tpl +104 -0
- aury/boot/commands/templates/project/aury_docs/14-mq.md.tpl +102 -0
- aury/boot/commands/templates/project/aury_docs/15-events.md.tpl +147 -0
- aury/boot/commands/templates/project/aury_docs/16-adapter.md.tpl +403 -0
- aury/boot/commands/templates/project/{CLI.md.tpl → aury_docs/99-cli.md.tpl} +19 -19
- aury/boot/commands/templates/project/config.py.tpl +10 -10
- aury/boot/commands/templates/project/env_templates/_header.tpl +10 -0
- aury/boot/commands/templates/project/env_templates/admin.tpl +49 -0
- aury/boot/commands/templates/project/env_templates/cache.tpl +14 -0
- aury/boot/commands/templates/project/env_templates/database.tpl +22 -0
- aury/boot/commands/templates/project/env_templates/log.tpl +18 -0
- aury/boot/commands/templates/project/env_templates/messaging.tpl +46 -0
- aury/boot/commands/templates/project/env_templates/rpc.tpl +28 -0
- aury/boot/commands/templates/project/env_templates/scheduler.tpl +18 -0
- aury/boot/commands/templates/project/env_templates/service.tpl +18 -0
- aury/boot/commands/templates/project/env_templates/storage.tpl +38 -0
- aury/boot/commands/templates/project/env_templates/third_party.tpl +43 -0
- aury/boot/commands/templates/project/modules/tasks.py.tpl +1 -1
- aury/boot/common/logging/__init__.py +26 -674
- aury/boot/common/logging/context.py +132 -0
- aury/boot/common/logging/decorators.py +118 -0
- aury/boot/common/logging/format.py +315 -0
- aury/boot/common/logging/setup.py +214 -0
- aury/boot/contrib/admin_console/auth.py +2 -3
- aury/boot/contrib/admin_console/install.py +1 -1
- aury/boot/domain/models/mixins.py +48 -1
- aury/boot/domain/pagination/__init__.py +94 -0
- aury/boot/domain/repository/impl.py +1 -1
- aury/boot/domain/repository/interface.py +1 -1
- aury/boot/domain/transaction/__init__.py +8 -9
- aury/boot/infrastructure/__init__.py +86 -29
- aury/boot/infrastructure/cache/backends.py +102 -18
- aury/boot/infrastructure/cache/base.py +12 -0
- aury/boot/infrastructure/cache/manager.py +153 -91
- aury/boot/infrastructure/channel/__init__.py +24 -0
- aury/boot/infrastructure/channel/backends/__init__.py +9 -0
- aury/boot/infrastructure/channel/backends/memory.py +83 -0
- aury/boot/infrastructure/channel/backends/redis.py +88 -0
- aury/boot/infrastructure/channel/base.py +92 -0
- aury/boot/infrastructure/channel/manager.py +203 -0
- aury/boot/infrastructure/clients/__init__.py +22 -0
- aury/boot/infrastructure/clients/rabbitmq/__init__.py +9 -0
- aury/boot/infrastructure/clients/rabbitmq/config.py +46 -0
- aury/boot/infrastructure/clients/rabbitmq/manager.py +288 -0
- aury/boot/infrastructure/clients/redis/__init__.py +28 -0
- aury/boot/infrastructure/clients/redis/config.py +51 -0
- aury/boot/infrastructure/clients/redis/manager.py +264 -0
- aury/boot/infrastructure/database/config.py +7 -16
- aury/boot/infrastructure/database/manager.py +16 -38
- aury/boot/infrastructure/events/__init__.py +18 -21
- aury/boot/infrastructure/events/backends/__init__.py +11 -0
- aury/boot/infrastructure/events/backends/memory.py +86 -0
- aury/boot/infrastructure/events/backends/rabbitmq.py +193 -0
- aury/boot/infrastructure/events/backends/redis.py +162 -0
- aury/boot/infrastructure/events/base.py +127 -0
- aury/boot/infrastructure/events/manager.py +224 -0
- aury/boot/infrastructure/mq/__init__.py +24 -0
- aury/boot/infrastructure/mq/backends/__init__.py +9 -0
- aury/boot/infrastructure/mq/backends/rabbitmq.py +179 -0
- aury/boot/infrastructure/mq/backends/redis.py +167 -0
- aury/boot/infrastructure/mq/base.py +143 -0
- aury/boot/infrastructure/mq/manager.py +239 -0
- aury/boot/infrastructure/scheduler/manager.py +7 -3
- aury/boot/infrastructure/storage/__init__.py +9 -9
- aury/boot/infrastructure/storage/base.py +17 -5
- aury/boot/infrastructure/storage/factory.py +0 -1
- aury/boot/infrastructure/tasks/__init__.py +2 -2
- aury/boot/infrastructure/tasks/config.py +5 -13
- aury/boot/infrastructure/tasks/manager.py +55 -33
- {aury_boot-0.0.4.dist-info → aury_boot-0.0.7.dist-info}/METADATA +20 -2
- aury_boot-0.0.7.dist-info/RECORD +197 -0
- aury/boot/commands/templates/project/DEVELOPMENT.md.tpl +0 -1397
- aury/boot/commands/templates/project/env.example.tpl +0 -213
- aury/boot/infrastructure/events/bus.py +0 -362
- aury/boot/infrastructure/events/config.py +0 -52
- aury/boot/infrastructure/events/consumer.py +0 -134
- aury/boot/infrastructure/events/models.py +0 -63
- aury_boot-0.0.4.dist-info/RECORD +0 -137
- {aury_boot-0.0.4.dist-info → aury_boot-0.0.7.dist-info}/WHEEL +0 -0
- {aury_boot-0.0.4.dist-info → aury_boot-0.0.7.dist-info}/entry_points.txt +0 -0
aury/boot/commands/generate.py
CHANGED
|
@@ -183,7 +183,7 @@ MODEL_BASE_CLASSES = {
|
|
|
183
183
|
"has_timestamps": True,
|
|
184
184
|
},
|
|
185
185
|
"AuditableStateModel": {
|
|
186
|
-
"desc": "
|
|
186
|
+
"desc": "int 主键 + 软删除(推荐)",
|
|
187
187
|
"features": ["id: int", "created_at", "updated_at", "deleted_at"],
|
|
188
188
|
"id_type": "int",
|
|
189
189
|
"has_timestamps": True,
|
|
@@ -195,7 +195,7 @@ MODEL_BASE_CLASSES = {
|
|
|
195
195
|
"has_timestamps": True,
|
|
196
196
|
},
|
|
197
197
|
"UUIDAuditableStateModel": {
|
|
198
|
-
"desc": "UUID 主键 +
|
|
198
|
+
"desc": "UUID 主键 + 软删除",
|
|
199
199
|
"features": ["id: UUID", "created_at", "updated_at", "deleted_at"],
|
|
200
200
|
"id_type": "uuid",
|
|
201
201
|
"has_timestamps": True,
|
|
@@ -219,13 +219,13 @@ MODEL_BASE_CLASSES = {
|
|
|
219
219
|
"has_timestamps": True,
|
|
220
220
|
},
|
|
221
221
|
"FullFeaturedModel": {
|
|
222
|
-
"desc": "
|
|
222
|
+
"desc": "int 主键 + 全功能",
|
|
223
223
|
"features": ["id: int", "created_at", "updated_at", "deleted_at", "version"],
|
|
224
224
|
"id_type": "int",
|
|
225
225
|
"has_timestamps": True,
|
|
226
226
|
},
|
|
227
227
|
"FullFeaturedUUIDModel": {
|
|
228
|
-
"desc": "
|
|
228
|
+
"desc": "UUID 主键 + 全功能",
|
|
229
229
|
"features": ["id: UUID", "created_at", "updated_at", "deleted_at", "version"],
|
|
230
230
|
"id_type": "uuid",
|
|
231
231
|
"has_timestamps": True,
|
|
@@ -250,9 +250,9 @@ class ModelDefinition:
|
|
|
250
250
|
def id_type(self) -> str:
|
|
251
251
|
"""获取 id 类型:'int' 或 'uuid'。"""
|
|
252
252
|
if self.base_class:
|
|
253
|
-
return MODEL_BASE_CLASSES.get(self.base_class, {}).get("id_type", "
|
|
254
|
-
#
|
|
255
|
-
return "
|
|
253
|
+
return MODEL_BASE_CLASSES.get(self.base_class, {}).get("id_type", "int")
|
|
254
|
+
# 默认使用 int 主键
|
|
255
|
+
return "int"
|
|
256
256
|
|
|
257
257
|
@property
|
|
258
258
|
def id_py_type(self) -> str:
|
|
@@ -373,14 +373,14 @@ def _collect_base_class_interactive() -> str:
|
|
|
373
373
|
info = MODEL_BASE_CLASSES[name]
|
|
374
374
|
# 推荐的加标记
|
|
375
375
|
desc = info["desc"]
|
|
376
|
-
if name == "
|
|
376
|
+
if name == "AuditableStateModel":
|
|
377
377
|
desc = f"[bold green]★ {desc}[/bold green]"
|
|
378
378
|
table.add_row(str(i), name, desc, ", ".join(info["features"]))
|
|
379
379
|
|
|
380
380
|
console.print(table)
|
|
381
381
|
console.print()
|
|
382
382
|
|
|
383
|
-
# 默认选择
|
|
383
|
+
# 默认选择 AuditableStateModel(第 4 个)
|
|
384
384
|
choice = Prompt.ask(
|
|
385
385
|
"请选择基类序号",
|
|
386
386
|
default="4",
|
|
@@ -556,16 +556,16 @@ def _generate_model_content(model: ModelDefinition) -> str:
|
|
|
556
556
|
features = base_info.get("features", [])
|
|
557
557
|
base_doc = f"继承 {base_class} 自动获得:\n - " + "\n - ".join(features) if features else f"继承 {base_class} 基类。"
|
|
558
558
|
elif model.soft_delete and model.timestamps:
|
|
559
|
-
base_class = "
|
|
560
|
-
base_doc = """继承
|
|
561
|
-
- id:
|
|
559
|
+
base_class = "AuditableStateModel"
|
|
560
|
+
base_doc = """继承 AuditableStateModel 自动获得:
|
|
561
|
+
- id: int 自增主键
|
|
562
562
|
- created_at: 创建时间
|
|
563
563
|
- updated_at: 更新时间
|
|
564
564
|
- deleted_at: 软删除时间戳"""
|
|
565
565
|
elif model.timestamps:
|
|
566
|
-
base_class = "
|
|
567
|
-
base_doc = """继承
|
|
568
|
-
- id:
|
|
566
|
+
base_class = "Model"
|
|
567
|
+
base_doc = """继承 Model 自动获得:
|
|
568
|
+
- id: int 自增主键
|
|
569
569
|
- created_at: 创建时间
|
|
570
570
|
- updated_at: 更新时间"""
|
|
571
571
|
else:
|
|
@@ -773,7 +773,7 @@ def generate_model(
|
|
|
773
773
|
),
|
|
774
774
|
base: str | None = typer.Option(
|
|
775
775
|
None, "--base", "-b",
|
|
776
|
-
help="模型基类(Model/
|
|
776
|
+
help="模型基类(AuditableStateModel/Model/FullFeaturedModel 等)"
|
|
777
777
|
),
|
|
778
778
|
force: bool = typer.Option(False, "--force", "-f", help="强制覆盖"),
|
|
779
779
|
no_soft_delete: bool = typer.Option(False, "--no-soft-delete", help="禁用软删除"),
|
|
@@ -803,9 +803,9 @@ def generate_model(
|
|
|
803
803
|
(length) - 字符串长度,如 str(100)
|
|
804
804
|
|
|
805
805
|
可用基类:
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
806
|
+
AuditableStateModel, Model, FullFeaturedModel,
|
|
807
|
+
UUIDModel, UUIDAuditableStateModel, FullFeaturedUUIDModel,
|
|
808
|
+
VersionedModel, VersionedTimestampedModel, VersionedUUIDModel
|
|
809
809
|
|
|
810
810
|
示例:
|
|
811
811
|
aury generate model user
|
|
@@ -1104,7 +1104,7 @@ def generate_crud(
|
|
|
1104
1104
|
),
|
|
1105
1105
|
base: str | None = typer.Option(
|
|
1106
1106
|
None, "--base", "-b",
|
|
1107
|
-
help="模型基类(Model/
|
|
1107
|
+
help="模型基类(AuditableStateModel/Model/FullFeaturedModel 等)"
|
|
1108
1108
|
),
|
|
1109
1109
|
force: bool = typer.Option(False, "--force", "-f", help="强制覆盖"),
|
|
1110
1110
|
no_soft_delete: bool = typer.Option(False, "--no-soft-delete", help="禁用软删除"),
|
|
@@ -1122,8 +1122,8 @@ def generate_crud(
|
|
|
1122
1122
|
|
|
1123
1123
|
示例:
|
|
1124
1124
|
aury generate crud user
|
|
1125
|
-
aury generate crud user --base
|
|
1126
|
-
aury generate crud user --base
|
|
1125
|
+
aury generate crud user --base AuditableStateModel # int 主键 + 软删除(推荐)
|
|
1126
|
+
aury generate crud user --base Model # int 主键 + 时间戳
|
|
1127
1127
|
aury generate crud user email:str:unique age:int? --force
|
|
1128
1128
|
aury generate crud article title:str(200) content:text status:str=draft
|
|
1129
1129
|
"""
|
aury/boot/commands/init.py
CHANGED
|
@@ -153,15 +153,29 @@ dev = [
|
|
|
153
153
|
TEMPLATE_FILE_MAP = {
|
|
154
154
|
"main.py": "main.py.tpl",
|
|
155
155
|
"config.py": "config.py.tpl",
|
|
156
|
-
".env.example": "
|
|
156
|
+
".env.example": "env_templates", # 特殊处理:拼接 env_templates/ 目录下的所有 .tpl 文件
|
|
157
157
|
".gitignore": "gitignore.tpl",
|
|
158
158
|
"README.md": "README.md.tpl",
|
|
159
|
-
"
|
|
160
|
-
"CLI.md": "CLI.md.tpl",
|
|
159
|
+
"AGENTS.md": "AGENTS.md.tpl",
|
|
161
160
|
"conftest.py": "conftest.py.tpl",
|
|
162
161
|
"admin_console/__init__.py": "admin_console_init.py.tpl",
|
|
163
162
|
}
|
|
164
163
|
|
|
164
|
+
# env 模板拼接顺序
|
|
165
|
+
ENV_TEMPLATE_ORDER = [
|
|
166
|
+
"_header.tpl",
|
|
167
|
+
"service.tpl",
|
|
168
|
+
"database.tpl",
|
|
169
|
+
"cache.tpl",
|
|
170
|
+
"log.tpl",
|
|
171
|
+
"admin.tpl",
|
|
172
|
+
"scheduler.tpl",
|
|
173
|
+
"messaging.tpl",
|
|
174
|
+
"storage.tpl",
|
|
175
|
+
"third_party.tpl",
|
|
176
|
+
"rpc.tpl",
|
|
177
|
+
]
|
|
178
|
+
|
|
165
179
|
# 模块 __init__.py 模板映射
|
|
166
180
|
MODULE_TEMPLATE_MAP = {
|
|
167
181
|
"api": "api.py.tpl",
|
|
@@ -171,8 +185,25 @@ MODULE_TEMPLATE_MAP = {
|
|
|
171
185
|
}
|
|
172
186
|
|
|
173
187
|
|
|
188
|
+
def _read_env_template() -> str:
|
|
189
|
+
"""读取并拼接 env_templates/ 目录下的所有模板文件。"""
|
|
190
|
+
env_dir = TEMPLATES_DIR / "env_templates"
|
|
191
|
+
parts = []
|
|
192
|
+
|
|
193
|
+
for tpl_name in ENV_TEMPLATE_ORDER:
|
|
194
|
+
tpl_path = env_dir / tpl_name
|
|
195
|
+
if tpl_path.exists():
|
|
196
|
+
parts.append(tpl_path.read_text(encoding="utf-8"))
|
|
197
|
+
|
|
198
|
+
return "\n".join(parts)
|
|
199
|
+
|
|
200
|
+
|
|
174
201
|
def _read_template(name: str) -> str:
|
|
175
202
|
"""读取模板文件。"""
|
|
203
|
+
# 特殊处理 .env.example:拼接 env_templates/ 目录
|
|
204
|
+
if name == ".env.example":
|
|
205
|
+
return _read_env_template()
|
|
206
|
+
|
|
176
207
|
# 先尝试从映射中查找 .tpl 文件
|
|
177
208
|
tpl_name = TEMPLATE_FILE_MAP.get(name)
|
|
178
209
|
if tpl_name:
|
|
@@ -245,22 +276,22 @@ def init_admin_console_module(
|
|
|
245
276
|
dest.write_text(content, encoding="utf-8")
|
|
246
277
|
result["file_created"] = True
|
|
247
278
|
|
|
248
|
-
# 2) 尝试在 .env.example 中开启
|
|
279
|
+
# 2) 尝试在 .env.example 中开启 ADMIN__* 配置
|
|
249
280
|
if enable_env:
|
|
250
281
|
env_example = base_path / ".env.example"
|
|
251
282
|
if env_example.exists():
|
|
252
283
|
try:
|
|
253
284
|
s = env_example.read_text(encoding="utf-8")
|
|
254
285
|
s2 = (
|
|
255
|
-
s.replace("#
|
|
256
|
-
.replace("#
|
|
257
|
-
.replace("#
|
|
286
|
+
s.replace("# ADMIN__ENABLED=false", "ADMIN__ENABLED=true")
|
|
287
|
+
.replace("# ADMIN__PATH=/api/admin-console", "ADMIN__PATH=/api/admin-console")
|
|
288
|
+
.replace("# ADMIN__AUTH__MODE=basic", "ADMIN__AUTH__MODE=basic")
|
|
258
289
|
.replace(
|
|
259
|
-
"#
|
|
260
|
-
"
|
|
290
|
+
"# ADMIN__AUTH__SECRET_KEY=CHANGE_ME_TO_A_RANDOM_SECRET",
|
|
291
|
+
"ADMIN__AUTH__SECRET_KEY=CHANGE_ME_TO_A_RANDOM_SECRET",
|
|
261
292
|
)
|
|
262
|
-
.replace("#
|
|
263
|
-
.replace("#
|
|
293
|
+
.replace("# ADMIN__AUTH__BASIC_USERNAME=admin", "ADMIN__AUTH__BASIC_USERNAME=admin")
|
|
294
|
+
.replace("# ADMIN__AUTH__BASIC_PASSWORD=change_me", "ADMIN__AUTH__BASIC_PASSWORD=change_me")
|
|
264
295
|
)
|
|
265
296
|
if s2 != s:
|
|
266
297
|
env_example.write_text(s2, encoding="utf-8")
|
|
@@ -712,8 +743,7 @@ def init(
|
|
|
712
743
|
(code_root / "admin_console" / "__init__.py", "admin_console/__init__.py", False),
|
|
713
744
|
(base_path / "tests" / "conftest.py", "conftest.py", False), # tests 放在项目根目录
|
|
714
745
|
(base_path / "README.md", "README.md", True), # 覆盖 uv init 创建的默认 README
|
|
715
|
-
(base_path / "
|
|
716
|
-
(base_path / "CLI.md", "CLI.md", False), # CLI 命令参考
|
|
746
|
+
(base_path / "AGENTS.md", "AGENTS.md", False), # AI 编程助手上下文
|
|
717
747
|
(base_path / ".gitignore", ".gitignore", False), # Git 忽略文件
|
|
718
748
|
]
|
|
719
749
|
|
|
@@ -806,13 +836,34 @@ def init(
|
|
|
806
836
|
else:
|
|
807
837
|
console.print(" [dim]ℹ️ migrations/ 目录已存在,跳过[/dim]")
|
|
808
838
|
|
|
809
|
-
# 5.
|
|
839
|
+
# 5. 生成开发文档 (aury_docs/) - 动态扫描模板目录
|
|
840
|
+
console.print("\n[bold]📚 生成开发文档...[/bold]")
|
|
841
|
+
aury_docs_tpl_dir = TEMPLATES_DIR / "aury_docs"
|
|
842
|
+
aury_docs_dir = base_path / "aury_docs"
|
|
843
|
+
aury_docs_dir.mkdir(parents=True, exist_ok=True)
|
|
844
|
+
docs_count = 0
|
|
845
|
+
if aury_docs_tpl_dir.exists():
|
|
846
|
+
for tpl_path in sorted(aury_docs_tpl_dir.glob("*.md.tpl")):
|
|
847
|
+
output_name = tpl_path.stem # 去掉 .tpl 后缀,保留 .md
|
|
848
|
+
output_path = aury_docs_dir / output_name
|
|
849
|
+
if output_path.exists() and not force:
|
|
850
|
+
continue
|
|
851
|
+
try:
|
|
852
|
+
content = tpl_path.read_text(encoding="utf-8")
|
|
853
|
+
content = content.format(**template_vars)
|
|
854
|
+
output_path.write_text(content, encoding="utf-8")
|
|
855
|
+
docs_count += 1
|
|
856
|
+
except Exception:
|
|
857
|
+
pass
|
|
858
|
+
console.print(f" [green]✅ 已生成 {docs_count} 个文档到 aury_docs/[/green]")
|
|
859
|
+
|
|
860
|
+
# 6. 生成 Docker 配置
|
|
810
861
|
if with_docker:
|
|
811
862
|
console.print("\n[bold]🐳 生成 Docker 配置...[/bold]")
|
|
812
863
|
from .docker import docker_init
|
|
813
864
|
docker_init(force=force)
|
|
814
865
|
|
|
815
|
-
#
|
|
866
|
+
# 7. 显示结果
|
|
816
867
|
console.print("\n")
|
|
817
868
|
|
|
818
869
|
tree = Tree(f"[bold cyan]{project_name}/[/bold cyan]")
|
|
@@ -821,8 +872,8 @@ def init(
|
|
|
821
872
|
tree.add("[dim]alembic.ini[/dim]")
|
|
822
873
|
tree.add("[dim]pyproject.toml[/dim]")
|
|
823
874
|
tree.add("[dim]README.md[/dim]")
|
|
824
|
-
tree.add("[dim]
|
|
825
|
-
tree.add("[
|
|
875
|
+
tree.add("[dim]AGENTS.md[/dim]")
|
|
876
|
+
tree.add("[blue]aury_docs/[/blue]")
|
|
826
877
|
if with_docker:
|
|
827
878
|
tree.add("[dim]Dockerfile[/dim]")
|
|
828
879
|
tree.add("[dim]docker-compose.yml[/dim]")
|
aury/boot/commands/server/app.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import contextlib
|
|
5
6
|
import os
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
import sys
|
|
@@ -339,13 +340,11 @@ def dev(
|
|
|
339
340
|
typer.echo(f" 应用模块: {app_module_path}")
|
|
340
341
|
|
|
341
342
|
# 在应用启动完成后打印一次服务地址
|
|
342
|
-
|
|
343
|
+
with contextlib.suppress(Exception):
|
|
343
344
|
app_instance.add_event_handler(
|
|
344
345
|
"startup",
|
|
345
346
|
lambda: typer.echo(f"✅ 服务已就绪: http://{server_host}:{server_port}"),
|
|
346
347
|
)
|
|
347
|
-
except Exception:
|
|
348
|
-
pass
|
|
349
348
|
|
|
350
349
|
# 默认包含/排除规则(watchfiles 支持)
|
|
351
350
|
reload_includes = [
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
> 这是给 AI 编程助手阅读的项目上下文文件。根据开发任务类型,阅读下方「开发任务文档索引」中对应的文档。
|
|
4
|
+
|
|
5
|
+
## 项目概述
|
|
6
|
+
|
|
7
|
+
- **项目名称**: {project_name}
|
|
8
|
+
- **包名**: {package_name}
|
|
9
|
+
- **框架**: [Aury Boot](https://github.com/AuriMyth/aury-boot)(基于 FastAPI + SQLAlchemy 2.0 的微服务框架)
|
|
10
|
+
- **Python 版本**: >= 3.13
|
|
11
|
+
- **包管理**: uv(推荐)或 pip
|
|
12
|
+
|
|
13
|
+
## 常用命令
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 开发服务器(热重载)
|
|
17
|
+
aury server dev
|
|
18
|
+
|
|
19
|
+
# 数据库迁移
|
|
20
|
+
aury migrate make -m "描述" # 生成迁移
|
|
21
|
+
aury migrate up # 执行迁移
|
|
22
|
+
aury migrate down # 回滚迁移
|
|
23
|
+
aury migrate status # 查看状态
|
|
24
|
+
aury migrate show # 查看历史
|
|
25
|
+
|
|
26
|
+
# 测试
|
|
27
|
+
pytest
|
|
28
|
+
pytest tests/test_xxx.py -v
|
|
29
|
+
|
|
30
|
+
# 代码检查
|
|
31
|
+
ruff check .
|
|
32
|
+
mypy {package_name}/
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> ⚠️ **重要**:数据库迁移文件**必须**使用 `aury migrate make` 命令生成,**禁止**手写迁移文件!
|
|
36
|
+
|
|
37
|
+
## 项目结构
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
{project_name}/
|
|
41
|
+
├── {package_name}/ # 主代码包
|
|
42
|
+
│ ├── models/ # SQLAlchemy ORM 模型
|
|
43
|
+
│ ├── repositories/ # 数据访问层(Repository 模式)
|
|
44
|
+
│ ├── services/ # 业务逻辑层
|
|
45
|
+
│ ├── schemas/ # Pydantic 请求/响应模型
|
|
46
|
+
│ ├── api/ # FastAPI 路由
|
|
47
|
+
│ ├── exceptions/ # 业务异常
|
|
48
|
+
│ ├── tasks/ # 异步任务(Dramatiq)
|
|
49
|
+
│ └── schedules/ # 定时任务
|
|
50
|
+
├── aury_docs/ # 开发文档(由 aury docs dev 生成)
|
|
51
|
+
├── tests/ # 测试
|
|
52
|
+
├── migrations/ # 数据库迁移
|
|
53
|
+
└── main.py # 应用入口
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## 重要提醒
|
|
57
|
+
|
|
58
|
+
> **修改代码前,必须先阅读对应的文档!**
|
|
59
|
+
>
|
|
60
|
+
> 框架的 API 可能与常见框架不同,不要猜测。请查看 `aury_docs/` 下对应的文档。
|
|
61
|
+
|
|
62
|
+
## 开发任务文档索引
|
|
63
|
+
|
|
64
|
+
根据你要开发的功能类型,**必须阅读**对应的文档:
|
|
65
|
+
|
|
66
|
+
### CRUD / 数据库相关(最常见)
|
|
67
|
+
|
|
68
|
+
开发 CRUD 功能时,按顺序阅读以下文档:
|
|
69
|
+
|
|
70
|
+
1. **[aury_docs/01-model.md](./aury_docs/01-model.md)** - Model 定义规范
|
|
71
|
+
- 基类选择(AuditableStateModel 等)
|
|
72
|
+
- 字段类型映射
|
|
73
|
+
- 约束定义(软删除模型的复合唯一约束)
|
|
74
|
+
|
|
75
|
+
2. **[aury_docs/02-repository.md](./aury_docs/02-repository.md)** - Repository 使用
|
|
76
|
+
- BaseRepository API
|
|
77
|
+
- Filters 语法(__gt, __like 等)
|
|
78
|
+
- 自动提交机制
|
|
79
|
+
|
|
80
|
+
3. **[aury_docs/03-service.md](./aury_docs/03-service.md)** - Service 编写与事务
|
|
81
|
+
- 事务装饰器 @transactional
|
|
82
|
+
- 跨 Service 调用
|
|
83
|
+
- 事务传播 / Savepoints / on_commit 回调
|
|
84
|
+
- SELECT FOR UPDATE
|
|
85
|
+
|
|
86
|
+
4. **[aury_docs/04-schema.md](./aury_docs/04-schema.md)** - Pydantic Schema
|
|
87
|
+
- 请求/响应模型
|
|
88
|
+
- 常用验证
|
|
89
|
+
|
|
90
|
+
5. **[aury_docs/05-api.md](./aury_docs/05-api.md)** - API 路由
|
|
91
|
+
- 路由编写示例
|
|
92
|
+
- 依赖注入模式
|
|
93
|
+
|
|
94
|
+
6. **[aury_docs/06-exception.md](./aury_docs/06-exception.md)** - 异常处理
|
|
95
|
+
- 内置异常
|
|
96
|
+
- 自定义异常
|
|
97
|
+
|
|
98
|
+
### 异步任务 / 定时任务
|
|
99
|
+
|
|
100
|
+
- **[aury_docs/08-scheduler.md](./aury_docs/08-scheduler.md)** - 定时任务(APScheduler)
|
|
101
|
+
- **[aury_docs/09-tasks.md](./aury_docs/09-tasks.md)** - 异步任务(Dramatiq)
|
|
102
|
+
|
|
103
|
+
### 基础设施
|
|
104
|
+
|
|
105
|
+
- **[aury_docs/07-cache.md](./aury_docs/07-cache.md)** - 缓存
|
|
106
|
+
- **[aury_docs/10-storage.md](./aury_docs/10-storage.md)** - 对象存储(S3/COS/OSS)
|
|
107
|
+
- **[aury_docs/11-logging.md](./aury_docs/11-logging.md)** - 日志
|
|
108
|
+
- **[aury_docs/12-admin.md](./aury_docs/12-admin.md)** - 管理后台(SQLAdmin)
|
|
109
|
+
- **[aury_docs/13-channel.md](./aury_docs/13-channel.md)** - 流式通道(SSE)
|
|
110
|
+
- **[aury_docs/14-mq.md](./aury_docs/14-mq.md)** - 消息队列
|
|
111
|
+
- **[aury_docs/15-events.md](./aury_docs/15-events.md)** - 事件总线
|
|
112
|
+
|
|
113
|
+
### 第三方集成
|
|
114
|
+
|
|
115
|
+
- **[aury_docs/16-adapter.md](./aury_docs/16-adapter.md)** - 第三方接口适配器(Mock/真实切换)
|
|
116
|
+
|
|
117
|
+
### 配置 / CLI / 环境变量
|
|
118
|
+
|
|
119
|
+
- **[aury_docs/00-overview.md](./aury_docs/00-overview.md)** - 项目概览与最佳实践
|
|
120
|
+
- **[aury_docs/99-cli.md](./aury_docs/99-cli.md)** - CLI 命令参考
|
|
121
|
+
- **[.env.example](./.env.example)** - 所有可用环境变量
|
|
122
|
+
|
|
123
|
+
## 代码规范
|
|
124
|
+
|
|
125
|
+
### Model 规范
|
|
126
|
+
|
|
127
|
+
- **必须**继承框架预定义基类,**不要**直接继承 `Base`
|
|
128
|
+
- **推荐**使用 `AuditableStateModel`(int 主键 + 时间戳 + 软删除)
|
|
129
|
+
- 软删除模型**必须**使用复合唯一约束(包含 `deleted_at`),不能单独使用 `unique=True`
|
|
130
|
+
- **不建议**使用数据库外键(`ForeignKey`),通过程序控制关系,便于分库分表和微服务拆分
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
# ✅ 正确
|
|
134
|
+
from aury.boot.domain.models import AuditableStateModel
|
|
135
|
+
|
|
136
|
+
class User(AuditableStateModel):
|
|
137
|
+
__tablename__ = "users"
|
|
138
|
+
email: Mapped[str] = mapped_column(String(255), index=True)
|
|
139
|
+
__table_args__ = (
|
|
140
|
+
UniqueConstraint("email", "deleted_at", name="uq_users_email_deleted"),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# ❌ 错误:直接继承 Base
|
|
144
|
+
from aury.boot.domain.models.base import Base
|
|
145
|
+
class User(Base): ...
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Service 规范
|
|
149
|
+
|
|
150
|
+
- 写操作**必须**使用 `@transactional` 装饰器
|
|
151
|
+
- 只读操作可以不加事务装饰器
|
|
152
|
+
- 跨 Service 调用通过共享 session 实现事务共享
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from aury.boot.domain.transaction import transactional
|
|
156
|
+
|
|
157
|
+
class UserService(BaseService):
|
|
158
|
+
@transactional
|
|
159
|
+
async def create(self, data: UserCreate) -> User:
|
|
160
|
+
# 自动事务管理
|
|
161
|
+
return await self.repo.create(data.model_dump())
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Manager API 规范
|
|
165
|
+
|
|
166
|
+
所有基础设施 Manager 统一使用 `initialize()` 方法初始化:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# ✅ 正确
|
|
170
|
+
from aury.boot.infrastructure.cache import CacheManager
|
|
171
|
+
cache = CacheManager.get_instance()
|
|
172
|
+
await cache.initialize(backend="redis", url="redis://localhost:6379")
|
|
173
|
+
|
|
174
|
+
from aury.boot.infrastructure.storage import StorageManager, StorageConfig
|
|
175
|
+
storage = StorageManager.get_instance()
|
|
176
|
+
await storage.initialize(StorageConfig(...))
|
|
177
|
+
|
|
178
|
+
from aury.boot.infrastructure.events import EventBusManager
|
|
179
|
+
events = EventBusManager.get_instance()
|
|
180
|
+
await events.initialize(backend="memory")
|
|
181
|
+
|
|
182
|
+
# ❗ 注意:没有 configure() 方法,配置直接传入 initialize()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 异常规范
|
|
186
|
+
|
|
187
|
+
- **必须**继承框架异常类,**不要**直接继承 `Exception`
|
|
188
|
+
- 使用框架内置异常:`NotFoundError`, `AlreadyExistsError`, `UnauthorizedError` 等
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
# ✅ 正确
|
|
192
|
+
from aury.boot.application.errors import NotFoundError
|
|
193
|
+
raise NotFoundError("用户不存在", resource=user_id)
|
|
194
|
+
|
|
195
|
+
# ❌ 错误
|
|
196
|
+
raise Exception("用户不存在")
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 响应规范
|
|
200
|
+
|
|
201
|
+
- **不要**自定义通用响应 Schema
|
|
202
|
+
- 使用框架内置:`BaseResponse`, `PaginationResponse`
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
from aury.boot.application.interfaces.egress import BaseResponse
|
|
206
|
+
return BaseResponse(code=200, message="成功", data=user)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## 禁止操作
|
|
210
|
+
|
|
211
|
+
- ❌ 不要直接修改 `aury/boot/` 框架代码
|
|
212
|
+
- ❌ 不要在 Model 中直接使用 `unique=True`(软删除模型)
|
|
213
|
+
- ❌ 不要自定义通用响应 Schema
|
|
214
|
+
- ❌ 不要在 Repository 之外直接操作 session
|
|
215
|
+
- ❌ 不要提交 `.env` 文件到版本库
|
|
216
|
+
|
|
217
|
+
## 需要确认的操作
|
|
218
|
+
|
|
219
|
+
- ⚠️ 添加新的 pip 依赖前请确认
|
|
220
|
+
- ⚠️ 修改数据库迁移前请确认
|
|
221
|
+
- ⚠️ 删除文件前请确认
|
|
@@ -106,6 +106,6 @@ aury worker
|
|
|
106
106
|
|
|
107
107
|
## 文档
|
|
108
108
|
|
|
109
|
-
- [
|
|
110
|
-
- [
|
|
109
|
+
- [AGENTS.md](./AGENTS.md) - AI 编程助手上下文
|
|
110
|
+
- [aury_docs/](./aury_docs/) - 开发文档(包含 Model/Service/API 等指南)
|
|
111
111
|
- [Aury Boot 文档](https://github.com/AuriMyth/aury-boot)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# {project_name} 开发指南
|
|
2
|
+
|
|
3
|
+
本文档基于 [Aury Boot](https://github.com/AuriMyth/aury-boot) 框架。
|
|
4
|
+
|
|
5
|
+
CLI 命令参考请查看 [99-cli.md](./99-cli.md)。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 目录结构
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
{project_name}/
|
|
13
|
+
├── {package_name}/ # 代码包(默认 app,可通过 aury init <pkg> 自定义)
|
|
14
|
+
│ ├── models/ # SQLAlchemy ORM 模型
|
|
15
|
+
│ ├── repositories/ # 数据访问层
|
|
16
|
+
│ ├── services/ # 业务逻辑层
|
|
17
|
+
│ ├── schemas/ # Pydantic 请求/响应模型
|
|
18
|
+
│ ├── api/ # FastAPI 路由
|
|
19
|
+
│ ├── exceptions/ # 业务异常
|
|
20
|
+
│ ├── tasks/ # 异步任务(Dramatiq)
|
|
21
|
+
│ └── schedules/ # 定时任务(Scheduler)
|
|
22
|
+
├── tests/ # 测试
|
|
23
|
+
├── migrations/ # 数据库迁移
|
|
24
|
+
└── main.py # 应用入口
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 最佳实践
|
|
30
|
+
|
|
31
|
+
1. **分层架构**:API → Service → Repository → Model
|
|
32
|
+
2. **事务管理**:在 Service 层使用 `@transactional`,只读操作可不加
|
|
33
|
+
3. **错误处理**:使用框架异常类,全局异常处理器统一处理
|
|
34
|
+
4. **配置管理**:使用 `.env` 文件,不提交到版本库
|
|
35
|
+
5. **日志记录**:使用框架 logger,支持结构化日志和链路追踪
|
|
36
|
+
6. **多实例配置**:环境变量格式 `{{PREFIX}}_{{INSTANCE}}_{{FIELD}}`
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 文档索引
|
|
41
|
+
|
|
42
|
+
### CRUD / 数据库
|
|
43
|
+
- [01-model.md](./01-model.md) - Model 定义
|
|
44
|
+
- [02-repository.md](./02-repository.md) - Repository 使用
|
|
45
|
+
- [03-service.md](./03-service.md) - Service 与事务
|
|
46
|
+
- [04-schema.md](./04-schema.md) - Pydantic Schema
|
|
47
|
+
- [05-api.md](./05-api.md) - API 路由
|
|
48
|
+
- [06-exception.md](./06-exception.md) - 异常处理
|
|
49
|
+
|
|
50
|
+
### 基础设施
|
|
51
|
+
- [07-cache.md](./07-cache.md) - 缓存
|
|
52
|
+
- [08-scheduler.md](./08-scheduler.md) - 定时任务
|
|
53
|
+
- [09-tasks.md](./09-tasks.md) - 异步任务
|
|
54
|
+
- [10-storage.md](./10-storage.md) - 对象存储
|
|
55
|
+
- [11-logging.md](./11-logging.md) - 日志
|
|
56
|
+
- [12-admin.md](./12-admin.md) - 管理后台
|
|
57
|
+
- [13-channel.md](./13-channel.md) - 流式通道(SSE)
|
|
58
|
+
- [14-mq.md](./14-mq.md) - 消息队列
|
|
59
|
+
- [15-events.md](./15-events.md) - 事件总线
|