@wneng/create-keel 0.3.6 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +206 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/templates/ci-gitee/files/PULL_REQUEST_TEMPLATE.md +15 -2
- package/src/templates/ci-gitee/files/pipeline.yml +62 -0
- package/src/templates/ci-github/files/PULL_REQUEST_TEMPLATE.md +15 -2
- package/src/templates/ci-github/files/ci.yml +160 -0
- package/src/templates/db-go-elasticsearch/files/Makefile +18 -0
- package/src/templates/db-go-elasticsearch/files/apply_templates.go +80 -0
- package/src/templates/db-go-elasticsearch/files/db-README.md +57 -0
- package/src/templates/db-go-elasticsearch/files/go.mod +7 -0
- package/src/templates/db-go-elasticsearch/files/index-template-init.json +25 -0
- package/src/templates/db-go-elasticsearch/fragment.yaml +22 -0
- package/src/templates/db-go-migrate-mysql/files/000001_init.down.sql +3 -0
- package/src/templates/db-go-migrate-mysql/files/000001_init.up.sql +35 -0
- package/src/templates/db-go-migrate-mysql/files/Makefile +33 -0
- package/src/templates/db-go-migrate-mysql/files/db-README.md +77 -0
- package/src/templates/db-go-migrate-mysql/files/go.mod +8 -0
- package/src/templates/db-go-migrate-mysql/fragment.yaml +22 -0
- package/src/templates/db-go-migrate-postgres/files/000001_init.down.sql +3 -0
- package/src/templates/db-go-migrate-postgres/files/000001_init.up.sql +32 -0
- package/src/templates/db-go-migrate-postgres/files/Makefile +31 -0
- package/src/templates/db-go-migrate-postgres/files/db-README.md +71 -0
- package/src/templates/db-go-migrate-postgres/files/go.mod +8 -0
- package/src/templates/db-go-migrate-postgres/fragment.yaml +22 -0
- package/src/templates/db-java-elasticsearch/files/EsTemplateApplier.java +86 -0
- package/src/templates/db-java-elasticsearch/files/db-README.md +63 -0
- package/src/templates/db-java-elasticsearch/files/index-template-init.json +25 -0
- package/src/templates/db-java-elasticsearch/files/pom.xml +134 -0
- package/src/templates/db-java-elasticsearch/fragment.yaml +19 -0
- package/src/templates/db-java-flyway-mysql/files/V1__init.sql +44 -0
- package/src/templates/db-java-flyway-mysql/files/application.yaml +39 -0
- package/src/templates/db-java-flyway-mysql/files/db-README.md +102 -0
- package/src/templates/db-java-flyway-mysql/files/pom.xml +172 -0
- package/src/templates/db-java-flyway-mysql/fragment.yaml +19 -0
- package/src/templates/db-java-flyway-postgres/files/V1__init.sql +40 -0
- package/src/templates/db-java-flyway-postgres/files/application.yaml +37 -0
- package/src/templates/db-java-flyway-postgres/files/db-README.md +75 -0
- package/src/templates/db-java-flyway-postgres/files/pom.xml +166 -0
- package/src/templates/db-java-flyway-postgres/fragment.yaml +19 -0
- package/src/templates/db-node-elasticsearch/files/apply-templates.cjs +60 -0
- package/src/templates/db-node-elasticsearch/files/db-README.md +76 -0
- package/src/templates/db-node-elasticsearch/files/index-template-init.json +26 -0
- package/src/templates/db-node-elasticsearch/files/package.json +26 -0
- package/src/templates/db-node-elasticsearch/fragment.yaml +19 -0
- package/src/templates/db-node-knex-mysql/files/db-README.md +90 -0
- package/src/templates/db-node-knex-mysql/files/knexfile.cjs +72 -0
- package/src/templates/db-node-knex-mysql/files/migrations-init.cjs +42 -0
- package/src/templates/db-node-knex-mysql/files/package.json +31 -0
- package/src/templates/db-node-knex-mysql/files/seeds-dev-fixtures.cjs +38 -0
- package/src/templates/db-node-knex-mysql/files/seeds-prod-dictionaries.cjs +25 -0
- package/src/templates/db-node-knex-mysql/fragment.yaml +25 -0
- package/src/templates/db-node-knex-postgres/files/db-README.md +81 -0
- package/src/templates/db-node-knex-postgres/files/knexfile.cjs +67 -0
- package/src/templates/db-node-knex-postgres/files/migrations-init.cjs +42 -0
- package/src/templates/db-node-knex-postgres/files/package.json +31 -0
- package/src/templates/db-node-knex-postgres/files/seeds-dev-fixtures.cjs +36 -0
- package/src/templates/db-node-knex-postgres/files/seeds-prod-dictionaries.cjs +26 -0
- package/src/templates/db-node-knex-postgres/fragment.yaml +25 -0
- package/src/templates/db-python-alembic-mysql/files/0001_init.py +70 -0
- package/src/templates/db-python-alembic-mysql/files/alembic.ini +47 -0
- package/src/templates/db-python-alembic-mysql/files/db-README.md +87 -0
- package/src/templates/db-python-alembic-mysql/files/env.py +71 -0
- package/src/templates/db-python-alembic-mysql/files/pyproject.toml +52 -0
- package/src/templates/db-python-alembic-mysql/files/script.py.mako +26 -0
- package/src/templates/db-python-alembic-mysql/fragment.yaml +25 -0
- package/src/templates/db-python-alembic-postgres/files/0001_init.py +62 -0
- package/src/templates/db-python-alembic-postgres/files/alembic.ini +45 -0
- package/src/templates/db-python-alembic-postgres/files/db-README.md +70 -0
- package/src/templates/db-python-alembic-postgres/files/env.py +62 -0
- package/src/templates/db-python-alembic-postgres/files/pyproject.toml +52 -0
- package/src/templates/db-python-alembic-postgres/files/script.py.mako +25 -0
- package/src/templates/db-python-alembic-postgres/fragment.yaml +25 -0
- package/src/templates/db-python-elasticsearch/files/apply_templates.py +55 -0
- package/src/templates/db-python-elasticsearch/files/db-README.md +57 -0
- package/src/templates/db-python-elasticsearch/files/index-template-init.json +25 -0
- package/src/templates/db-python-elasticsearch/files/pyproject.toml +50 -0
- package/src/templates/db-python-elasticsearch/fragment.yaml +19 -0
- package/src/templates/docs-skeleton/files/governance-change-tiers.md +135 -76
- package/src/templates/docs-skeleton/files/governance-database.md +150 -0
- package/src/templates/docs-skeleton/fragment.yaml +3 -0
- package/src/templates/root-files/files/AGENTS.md +35 -17
- package/src/templates/server-python/files/README.md +75 -2
- package/src/templates/server-python/files/app-init.py +11 -1
- package/src/templates/server-python/files/config.py +40 -0
- package/src/templates/server-python/files/main.py +62 -0
- package/src/templates/server-python/files/pyproject.toml +14 -1
- package/src/templates/server-python/files/test_healthz.py +36 -0
- package/src/templates/server-python/fragment.yaml +10 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
; Alembic configuration for <%= it.options.projectName %>-server (PostgreSQL).
|
|
2
|
+
;
|
|
3
|
+
; Connection string is read from DATABASE_URL at runtime (see env.py).
|
|
4
|
+
|
|
5
|
+
[alembic]
|
|
6
|
+
script_location = db/migrations
|
|
7
|
+
prepend_sys_path = .
|
|
8
|
+
version_path_separator = os
|
|
9
|
+
sqlalchemy.url =
|
|
10
|
+
|
|
11
|
+
output_encoding = utf-8
|
|
12
|
+
|
|
13
|
+
[loggers]
|
|
14
|
+
keys = root,sqlalchemy,alembic
|
|
15
|
+
|
|
16
|
+
[handlers]
|
|
17
|
+
keys = console
|
|
18
|
+
|
|
19
|
+
[formatters]
|
|
20
|
+
keys = generic
|
|
21
|
+
|
|
22
|
+
[logger_root]
|
|
23
|
+
level = WARN
|
|
24
|
+
handlers = console
|
|
25
|
+
qualname =
|
|
26
|
+
|
|
27
|
+
[logger_sqlalchemy]
|
|
28
|
+
level = WARN
|
|
29
|
+
handlers =
|
|
30
|
+
qualname = sqlalchemy.engine
|
|
31
|
+
|
|
32
|
+
[logger_alembic]
|
|
33
|
+
level = INFO
|
|
34
|
+
handlers =
|
|
35
|
+
qualname = alembic
|
|
36
|
+
|
|
37
|
+
[handler_console]
|
|
38
|
+
class = StreamHandler
|
|
39
|
+
args = (sys.stderr,)
|
|
40
|
+
level = NOTSET
|
|
41
|
+
formatter = generic
|
|
42
|
+
|
|
43
|
+
[formatter_generic]
|
|
44
|
+
format = %(levelname)-5.5s [%(name)s] %(message)s
|
|
45
|
+
datefmt = %Y-%m-%d %H:%M:%S
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# server/db/
|
|
2
|
+
|
|
3
|
+
数据库迁移、种子数据、本地数据库工具的入口。
|
|
4
|
+
|
|
5
|
+
> 跨项目的数据库归属规则(哪类 SQL 放哪个目录、与 `contracts/` 如何对齐)见 [`docs/governance/database.md`](../../docs/governance/database.md)。
|
|
6
|
+
|
|
7
|
+
## 工具与版本
|
|
8
|
+
|
|
9
|
+
| 项 | 值 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| 数据库 | PostgreSQL 14+ |
|
|
12
|
+
| 迁移工具 | [Alembic](https://alembic.sqlalchemy.org) `1.13.3` |
|
|
13
|
+
| ORM | SQLAlchemy `2.0.36` |
|
|
14
|
+
| 驱动 | `psycopg[binary]` `3.2.3`(psycopg v3) |
|
|
15
|
+
|
|
16
|
+
工具版本在 `pyproject.toml` 钉死,并镜像到 `docs/03-工程规范与研发基础设施/tech-stack-server.md`。
|
|
17
|
+
|
|
18
|
+
## 目录布局
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
server/
|
|
22
|
+
├── pyproject.toml
|
|
23
|
+
├── alembic.ini
|
|
24
|
+
└── db/
|
|
25
|
+
├── README.md
|
|
26
|
+
└── migrations/
|
|
27
|
+
├── env.py
|
|
28
|
+
├── script.py.mako
|
|
29
|
+
└── versions/
|
|
30
|
+
└── <NNNN>_<description>.py
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## 常用命令
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
alembic revision -m "create orders table" # 新建迁移
|
|
37
|
+
alembic revision --autogenerate -m "..." # 配合 SQLAlchemy 模型
|
|
38
|
+
alembic upgrade head # 升到最新
|
|
39
|
+
alembic downgrade -1 # 回滚一版
|
|
40
|
+
alembic current # 查看当前版本
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
环境变量 `DATABASE_URL`(默认 `postgresql+psycopg://postgres:@127.0.0.1:5432/<project>_dev`)。
|
|
44
|
+
|
|
45
|
+
## prod vs dev seeds
|
|
46
|
+
|
|
47
|
+
| 类型 | 位置 |
|
|
48
|
+
|---|---|
|
|
49
|
+
| 生产字典(必装) | 写进 `versions/` 的 revision 中(ON CONFLICT DO NOTHING) |
|
|
50
|
+
| 开发样例 | `server/db/seeds/dev/` 下手动执行 |
|
|
51
|
+
|
|
52
|
+
字典类生产种子真值在 `contracts/dictionaries/enums.yaml`;当前手动同步。
|
|
53
|
+
|
|
54
|
+
## 改动分级(参见 `docs/governance/change-tiers.md`)
|
|
55
|
+
|
|
56
|
+
| 改动 | Tier |
|
|
57
|
+
|---|---|
|
|
58
|
+
| 新建 revision 加表 / 加字段 | 3 |
|
|
59
|
+
| 修改既有 revision | **不允许** |
|
|
60
|
+
| 删字段 / 改类型(破坏性) | 4 |
|
|
61
|
+
| 改 dev seed | 1/2 |
|
|
62
|
+
| 改字典数据 | 3(同步 contracts/dictionaries/) |
|
|
63
|
+
| 升级 Alembic / SQLAlchemy / psycopg | 2,但同步改 tech-stack-server.md |
|
|
64
|
+
|
|
65
|
+
## CI 行为
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
alembic upgrade head
|
|
69
|
+
alembic downgrade base
|
|
70
|
+
```
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Alembic environment for PostgreSQL (psycopg v3).
|
|
2
|
+
|
|
3
|
+
Reads DATABASE_URL from env (or falls back to a localhost Postgres DSN);
|
|
4
|
+
imports the application's SQLAlchemy metadata for autogenerate support.
|
|
5
|
+
|
|
6
|
+
Edit `target_metadata` to point at your app's Base.metadata once you
|
|
7
|
+
introduce ORM models.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import os
|
|
11
|
+
from logging.config import fileConfig
|
|
12
|
+
|
|
13
|
+
from alembic import context
|
|
14
|
+
from sqlalchemy import engine_from_config, pool
|
|
15
|
+
|
|
16
|
+
config = context.config
|
|
17
|
+
|
|
18
|
+
if config.config_file_name is not None:
|
|
19
|
+
fileConfig(config.config_file_name)
|
|
20
|
+
|
|
21
|
+
config.set_main_option(
|
|
22
|
+
"sqlalchemy.url",
|
|
23
|
+
os.environ.get(
|
|
24
|
+
"DATABASE_URL",
|
|
25
|
+
"postgresql+psycopg://postgres:@127.0.0.1:5432/" + "<%= it.options.projectName.replace(/-/g, '_') %>" + "_dev",
|
|
26
|
+
),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
target_metadata = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def run_migrations_offline() -> None:
|
|
33
|
+
url = config.get_main_option("sqlalchemy.url")
|
|
34
|
+
context.configure(
|
|
35
|
+
url=url,
|
|
36
|
+
target_metadata=target_metadata,
|
|
37
|
+
literal_binds=True,
|
|
38
|
+
dialect_opts={"paramstyle": "named"},
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
with context.begin_transaction():
|
|
42
|
+
context.run_migrations()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def run_migrations_online() -> None:
|
|
46
|
+
connectable = engine_from_config(
|
|
47
|
+
config.get_section(config.config_ini_section, {}),
|
|
48
|
+
prefix="sqlalchemy.",
|
|
49
|
+
poolclass=pool.NullPool,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
with connectable.connect() as connection:
|
|
53
|
+
context.configure(connection=connection, target_metadata=target_metadata)
|
|
54
|
+
|
|
55
|
+
with context.begin_transaction():
|
|
56
|
+
context.run_migrations()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
if context.is_offline_mode():
|
|
60
|
+
run_migrations_offline()
|
|
61
|
+
else:
|
|
62
|
+
run_migrations_online()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "<%= it.options.projectName %>-server"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
requires-python = ">=3.11"
|
|
5
|
+
dependencies = [
|
|
6
|
+
"fastapi==0.115.5",
|
|
7
|
+
"uvicorn[standard]==0.32.0",
|
|
8
|
+
"pydantic==2.9.2",
|
|
9
|
+
"pydantic-settings==2.6.1",
|
|
10
|
+
"alembic==1.13.3",
|
|
11
|
+
"sqlalchemy==2.0.36",
|
|
12
|
+
"psycopg[binary]==3.2.3",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.optional-dependencies]
|
|
16
|
+
dev = [
|
|
17
|
+
"ruff>=0.6.8",
|
|
18
|
+
"mypy>=1.11.0",
|
|
19
|
+
"pytest>=8.3.0",
|
|
20
|
+
"pytest-asyncio>=0.24.0",
|
|
21
|
+
"httpx>=0.27.0",
|
|
22
|
+
"pip-audit>=2.7.0",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[tool.ruff]
|
|
26
|
+
line-length = 100
|
|
27
|
+
target-version = "py311"
|
|
28
|
+
extend-exclude = ["generated", ".venv", "db/migrations/versions"]
|
|
29
|
+
|
|
30
|
+
[tool.ruff.lint]
|
|
31
|
+
select = ["E", "F", "W", "I", "B", "UP", "N"]
|
|
32
|
+
ignore = []
|
|
33
|
+
|
|
34
|
+
[tool.ruff.format]
|
|
35
|
+
quote-style = "double"
|
|
36
|
+
indent-style = "space"
|
|
37
|
+
line-ending = "lf"
|
|
38
|
+
|
|
39
|
+
[tool.mypy]
|
|
40
|
+
python_version = "3.11"
|
|
41
|
+
strict_optional = true
|
|
42
|
+
disallow_untyped_defs = true
|
|
43
|
+
warn_unused_ignores = true
|
|
44
|
+
exclude = ["generated", ".venv", "db/migrations/versions"]
|
|
45
|
+
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
48
|
+
asyncio_mode = "auto"
|
|
49
|
+
|
|
50
|
+
[tool.setuptools.packages.find]
|
|
51
|
+
include = ["app*"]
|
|
52
|
+
exclude = ["tests*", "generated*", "db*"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""${message}
|
|
2
|
+
|
|
3
|
+
Revision ID: ${up_revision}
|
|
4
|
+
Revises: ${down_revision | comma,n}
|
|
5
|
+
Create Date: ${create_date}
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from typing import Sequence, Union
|
|
9
|
+
|
|
10
|
+
from alembic import op
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
${imports if imports else ""}
|
|
13
|
+
|
|
14
|
+
revision: str = ${repr(up_revision)}
|
|
15
|
+
down_revision: Union[str, None] = ${repr(down_revision)}
|
|
16
|
+
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
|
|
17
|
+
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def upgrade() -> None:
|
|
21
|
+
${upgrades if upgrades else "pass"}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def downgrade() -> None:
|
|
25
|
+
${downgrades if downgrades else "pass"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: db-python-alembic-postgres
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
appliesWhen:
|
|
4
|
+
backend: python
|
|
5
|
+
database: postgres
|
|
6
|
+
priority: 40
|
|
7
|
+
files:
|
|
8
|
+
- from: files/pyproject.toml
|
|
9
|
+
to: server/pyproject.toml
|
|
10
|
+
render: true
|
|
11
|
+
- from: files/alembic.ini
|
|
12
|
+
to: server/alembic.ini
|
|
13
|
+
render: true
|
|
14
|
+
- from: files/env.py
|
|
15
|
+
to: server/db/migrations/env.py
|
|
16
|
+
render: false
|
|
17
|
+
- from: files/script.py.mako
|
|
18
|
+
to: server/db/migrations/script.py.mako
|
|
19
|
+
render: false
|
|
20
|
+
- from: files/0001_init.py
|
|
21
|
+
to: server/db/migrations/versions/0001_init.py
|
|
22
|
+
render: false
|
|
23
|
+
- from: files/db-README.md
|
|
24
|
+
to: server/db/README.md
|
|
25
|
+
render: true
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Idempotent Elasticsearch index-template applier (Python backend).
|
|
2
|
+
|
|
3
|
+
ES 没有事务性 DDL;"migration" 退化为把 db/index-templates/*.json 全部 PUT 一次。
|
|
4
|
+
ES 自身保证 PUT 同名 template 的幂等性。
|
|
5
|
+
|
|
6
|
+
改动 tier(参见 docs/governance/change-tiers.md):
|
|
7
|
+
- 新增 template 文件:Tier 3
|
|
8
|
+
- 修改既有 template 的 mapping 字段:Tier 4(破坏性 - 可能 reindex)
|
|
9
|
+
- 仅改 priority / 新增 alias:Tier 2
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from elasticsearch import Elasticsearch
|
|
20
|
+
|
|
21
|
+
TEMPLATE_DIR = Path(__file__).parent / "index-templates"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main() -> None:
|
|
25
|
+
url = os.environ.get("ELASTICSEARCH_URL", "http://127.0.0.1:9200")
|
|
26
|
+
username = os.environ.get("ELASTICSEARCH_USERNAME")
|
|
27
|
+
password = os.environ.get("ELASTICSEARCH_PASSWORD")
|
|
28
|
+
|
|
29
|
+
kwargs: dict[str, object] = {"hosts": [url]}
|
|
30
|
+
if username and password:
|
|
31
|
+
kwargs["basic_auth"] = (username, password)
|
|
32
|
+
|
|
33
|
+
client = Elasticsearch(**kwargs)
|
|
34
|
+
client.cluster.health(wait_for_status="yellow", timeout="30s")
|
|
35
|
+
|
|
36
|
+
files = sorted(p for p in TEMPLATE_DIR.glob("*.json"))
|
|
37
|
+
if not files:
|
|
38
|
+
print(f"no index templates found in {TEMPLATE_DIR}")
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
for path in files:
|
|
42
|
+
body = json.loads(path.read_text(encoding="utf-8"))
|
|
43
|
+
name = path.stem # filename minus .json
|
|
44
|
+
client.indices.put_index_template(name=name, body=body)
|
|
45
|
+
print(f"✓ applied {name}")
|
|
46
|
+
|
|
47
|
+
print(f"done; {len(files)} template(s) applied to {url}")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
try:
|
|
52
|
+
main()
|
|
53
|
+
except Exception as e: # noqa: BLE001
|
|
54
|
+
print(f"✗ failed: {e}", file=sys.stderr)
|
|
55
|
+
sys.exit(1)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# server/db/
|
|
2
|
+
|
|
3
|
+
Elasticsearch index-template 入口(Python 后端)。
|
|
4
|
+
|
|
5
|
+
> 跨项目的数据库归属规则见 [`docs/governance/database.md`](../../docs/governance/database.md)。
|
|
6
|
+
|
|
7
|
+
## "Migration" 的语义
|
|
8
|
+
|
|
9
|
+
**Elasticsearch 没有事务性 DDL,本目录里的 JSON 不是迁移文件。**
|
|
10
|
+
|
|
11
|
+
每个 `db/index-templates/*.json` 是一个 [Index Template v2](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-templates.html)。`apply_templates.py` 按文件名字典序遍历目录,对每个文件 PUT;ES 自身保证幂等。
|
|
12
|
+
|
|
13
|
+
## 工具与版本
|
|
14
|
+
|
|
15
|
+
| 项 | 值 |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Elasticsearch | 8.15+ |
|
|
18
|
+
| Python 客户端 | `elasticsearch` `8.15.1` |
|
|
19
|
+
|
|
20
|
+
## 目录布局
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
server/
|
|
24
|
+
├── pyproject.toml
|
|
25
|
+
└── db/
|
|
26
|
+
├── README.md
|
|
27
|
+
├── apply_templates.py # 幂等 applier
|
|
28
|
+
└── index-templates/
|
|
29
|
+
└── <utc-ts>_<description>.json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 常用命令
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
python -m server.db.apply_templates
|
|
36
|
+
# 或
|
|
37
|
+
python server/db/apply_templates.py
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
环境变量 `ELASTICSEARCH_URL`(默认 `http://127.0.0.1:9200`)、`ELASTICSEARCH_USERNAME` / `ELASTICSEARCH_PASSWORD`(可选)。
|
|
41
|
+
|
|
42
|
+
## 改动分级(参见 `docs/governance/change-tiers.md`)
|
|
43
|
+
|
|
44
|
+
| 改动 | Tier |
|
|
45
|
+
|---|---|
|
|
46
|
+
| 新增 template 文件 | 3 |
|
|
47
|
+
| 修改既有 template 的 mapping 字段 | 4(破坏性 - 可能 reindex) |
|
|
48
|
+
| 仅改 priority / 新增 alias / 改 settings.refresh_interval | 2 |
|
|
49
|
+
| 删除 template | 4 |
|
|
50
|
+
|
|
51
|
+
## 与 `contracts/asyncapi/` 的同步
|
|
52
|
+
|
|
53
|
+
事件 ingest 的 schema 真值在 `contracts/asyncapi/asyncapi.yaml`;index-template 的 mapping 应当与之**对齐**。当前手动同步。
|
|
54
|
+
|
|
55
|
+
## CI 行为
|
|
56
|
+
|
|
57
|
+
CI 起一个 ES 8 service container;脚本失败 = CI 红。
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"index_patterns": ["events-*"],
|
|
3
|
+
"priority": 100,
|
|
4
|
+
"template": {
|
|
5
|
+
"settings": {
|
|
6
|
+
"number_of_shards": 1,
|
|
7
|
+
"number_of_replicas": 1,
|
|
8
|
+
"refresh_interval": "5s"
|
|
9
|
+
},
|
|
10
|
+
"mappings": {
|
|
11
|
+
"properties": {
|
|
12
|
+
"@timestamp": { "type": "date" },
|
|
13
|
+
"tenant_id": { "type": "keyword" },
|
|
14
|
+
"event_type": { "type": "keyword" },
|
|
15
|
+
"user_id": { "type": "keyword" },
|
|
16
|
+
"payload": { "type": "object", "dynamic": true },
|
|
17
|
+
"trace_id": { "type": "keyword" }
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"_meta": {
|
|
22
|
+
"description": "Sample event-stream template. Replace mappings with your domain fields.",
|
|
23
|
+
"managed_by": "@wneng/create-keel"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "<%= it.options.projectName %>-server"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
requires-python = ">=3.11"
|
|
5
|
+
dependencies = [
|
|
6
|
+
"fastapi==0.115.5",
|
|
7
|
+
"uvicorn[standard]==0.32.0",
|
|
8
|
+
"pydantic==2.9.2",
|
|
9
|
+
"pydantic-settings==2.6.1",
|
|
10
|
+
"elasticsearch==8.15.1",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
[project.optional-dependencies]
|
|
14
|
+
dev = [
|
|
15
|
+
"ruff>=0.6.8",
|
|
16
|
+
"mypy>=1.11.0",
|
|
17
|
+
"pytest>=8.3.0",
|
|
18
|
+
"pytest-asyncio>=0.24.0",
|
|
19
|
+
"httpx>=0.27.0",
|
|
20
|
+
"pip-audit>=2.7.0",
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[tool.ruff]
|
|
24
|
+
line-length = 100
|
|
25
|
+
target-version = "py311"
|
|
26
|
+
extend-exclude = ["generated", ".venv"]
|
|
27
|
+
|
|
28
|
+
[tool.ruff.lint]
|
|
29
|
+
select = ["E", "F", "W", "I", "B", "UP", "N"]
|
|
30
|
+
ignore = []
|
|
31
|
+
|
|
32
|
+
[tool.ruff.format]
|
|
33
|
+
quote-style = "double"
|
|
34
|
+
indent-style = "space"
|
|
35
|
+
line-ending = "lf"
|
|
36
|
+
|
|
37
|
+
[tool.mypy]
|
|
38
|
+
python_version = "3.11"
|
|
39
|
+
strict_optional = true
|
|
40
|
+
disallow_untyped_defs = true
|
|
41
|
+
warn_unused_ignores = true
|
|
42
|
+
exclude = ["generated", ".venv"]
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
testpaths = ["tests"]
|
|
46
|
+
asyncio_mode = "auto"
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.packages.find]
|
|
49
|
+
include = ["app*"]
|
|
50
|
+
exclude = ["tests*", "generated*", "db*"]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: db-python-elasticsearch
|
|
2
|
+
version: 1.0.0
|
|
3
|
+
appliesWhen:
|
|
4
|
+
backend: python
|
|
5
|
+
database: elasticsearch
|
|
6
|
+
priority: 40
|
|
7
|
+
files:
|
|
8
|
+
- from: files/pyproject.toml
|
|
9
|
+
to: server/pyproject.toml
|
|
10
|
+
render: true
|
|
11
|
+
- from: files/apply_templates.py
|
|
12
|
+
to: server/db/apply_templates.py
|
|
13
|
+
render: false
|
|
14
|
+
- from: files/index-template-init.json
|
|
15
|
+
to: server/db/index-templates/20260101000000_init.json
|
|
16
|
+
render: false
|
|
17
|
+
- from: files/db-README.md
|
|
18
|
+
to: server/db/README.md
|
|
19
|
+
render: true
|