diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..bbab988
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,57 @@
+FROM debian:bookworm-slim AS builder
+
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends ca-certificates && \
+ rm -rf /var/lib/apt/lists/*
+
+COPY build/chongming /tmp/chongming
+
+RUN mkdir -p /tmp/rootfs/app && \
+ # === 临时目录 ===
+ mkdir -p /tmp/rootfs/tmp && \
+ chmod 1777 /tmp/rootfs/tmp && \
+ # === 数据目录 ===
+ mkdir -p /tmp/rootfs/app/data && \
+ chmod 777 /tmp/rootfs/app/data && \
+ # === 解释器目录 ===
+ mkdir -p /tmp/rootfs/lib64 && \
+ mkdir -p /tmp/rootfs/lib/x86_64-linux-gnu && \
+ cp /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ ln -s /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/rootfs/lib64/ld-linux-x86-64.so.2 && \
+ # === 依赖库 ===
+ cp /lib/x86_64-linux-gnu/libdl.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ cp /lib/x86_64-linux-gnu/libz.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ cp /lib/x86_64-linux-gnu/libpthread.so.0 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ cp /lib/x86_64-linux-gnu/libc.so.6 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ cp /lib/x86_64-linux-gnu/librt.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ cp /lib/x86_64-linux-gnu/libm.so.6 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ cp /lib/x86_64-linux-gnu/libutil.so.1 /tmp/rootfs/lib/x86_64-linux-gnu/ && \
+ cp /lib/x86_64-linux-gnu/libnss_dns.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \
+ cp /lib/x86_64-linux-gnu/libnss_files.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \
+ cp /lib/x86_64-linux-gnu/libresolv.so.2 /tmp/rootfs/lib/x86_64-linux-gnu/ 2>/dev/null || true && \
+ # === 时区数据 ===
+ mkdir -p /tmp/rootfs/usr/share/zoneinfo && \
+ cp -r /usr/share/zoneinfo/Asia /tmp/rootfs/usr/share/zoneinfo/ && \
+ cp /usr/share/zoneinfo/UTC /tmp/rootfs/usr/share/zoneinfo/ && \
+ # === 证书和 DNS ===
+ mkdir -p /tmp/rootfs/etc/ssl/certs && \
+ cp /etc/ssl/certs/ca-certificates.crt /tmp/rootfs/etc/ssl/certs/ && \
+ echo "hosts: files dns" > /tmp/rootfs/etc/nsswitch.conf && \
+ # === /proc /sys /dev ===
+ mkdir -p /tmp/rootfs/proc /tmp/rootfs/sys /tmp/rootfs/dev
+
+FROM scratch
+
+COPY --from=builder /tmp/rootfs/ /
+
+COPY build/chongming /app/chongming
+COPY build/config.toml /app/config.toml
+COPY build/resources/ /app/resources/
+COPY build/static.svfs /app/static.svfs
+COPY build/data /app/data
+
+WORKDIR /app
+
+EXPOSE 8000
+
+CMD ["./chongming"]
\ No newline at end of file
diff --git a/README.md b/README.md
index 53b0c21..fdba573 100644
--- a/README.md
+++ b/README.md
@@ -76,9 +76,6 @@ docker load -i chongming_latest.tar
运行镜像
```shell
-mkdir -p /data/chongming
-docker run -d -p 8000:8000 \
- -v /data/chongming/database.db:/app/database.db \
- -v /data/chongming/uploads:/app/uploads \
- --name chongming chongming:latest
+sudo chmod 777 ./deploy.sh
+./deploy.sh
```
diff --git a/config.toml b/config.toml
index 1e9ef33..0658d0d 100644
--- a/config.toml
+++ b/config.toml
@@ -1,27 +1,27 @@
[default]
+app.debug = false
+app.description = "基于 FastAPI 的 chongming 打包脚手架"
app.name = "chongming"
app.version = "chongming"
-app.description = "基于 FastAPI 的 chongming 打包脚手架"
-app.debug = false
env = "development"
prefix = "/api/v1"
upload_path = "uploads"
[database]
+database_path = "./data/database.db"
type = "sqlite"
-url = "sqlite+aiosqlite:///./database.db"
-generate_schemas = true # 生产环境使用迁移工具
+url = "sqlite+aiosqlite:///./data/database.db"
[database.sqlite]
+connect_args.check_same_thread = false
+connect_args.timeout = 15
echo = true
echo_pool = true
-pool_size = 20
max_overflow = 10
-pool_timeout = 30
-pool_recycle = 300
pool_pre_ping = true
-connect_args.timeout = 15
-connect_args.check_same_thread = false
+pool_recycle = 300
+pool_size = 20
+pool_timeout = 30
[scheduler]
job_store_path = "scheduler_jobs.db"
@@ -30,61 +30,61 @@ job_store_path = "scheduler_jobs.db"
cache_store_path = "./"
[security]
-secret_key = "your-secret-key-change-in-production"
-algorithm = "HS256"
access_token_expire_minutes = 30
-refresh_token_expire_days = 7
+algorithm = "HS256"
max_sessions_per_user = 5
+refresh_token_expire_days = 7
+secret_key = "your-secret-key-change-in-production"
[development]
-env = "development"
debug = true
+env = "development"
[development.server]
+access_log = false
host = "127.0.0.1"
port = 8000
reload = true
-access_log = false
[development.logging]
-level = "DEBUG"
file = "logs"
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+level = "DEBUG"
[development.cors]
-allow_origins = ["*"]
allow_credentials = true
-allow_methods = ["*"]
allow_headers = ["*"]
+allow_methods = ["*"]
+allow_origins = ["*"]
[production]
-env = "production"
debug = false
+env = "production"
[production.server]
+access_log = false
host = "0.0.0.0"
port = 8000
reload = false
workers = 4
-access_log = false
[production.logging]
-level = "INFO"
-file = "logs"
-format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
-max_size = 10485760 # 10MB
-backup_count = 5 # 最多保存 10 个日志文件
+backup_count = 5 # 最多保存 10 个日志文件
+file = "logs"
+format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+level = "INFO"
+max_size = 10485760 # 10MB
[production.cors]
-allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
allow_credentials = true
-allow_methods = ["GET", "POST", "PUT", "DELETE"]
allow_headers = ["Authorization", "Content-Type"]
+allow_methods = ["GET", "POST", "PUT", "DELETE"]
+allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
[production.module_system]
-type = "module-bank"
path = ["resources/app.mbank", "resources/plugins.mbank"]
+type = "module-bank"
[production.file_system]
-type = "svfs"
path = "static.svfs"
+type = "svfs"
diff --git a/deploy.sh b/deploy.sh
new file mode 100755
index 0000000..b5d1b4b
--- /dev/null
+++ b/deploy.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+# deploy.sh - chongming 快速部署脚本
+set -e
+
+# 颜色输出
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m'
+
+log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
+log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
+log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
+
+# 配置
+IMAGE="chongming:latest"
+CONTAINER="chongming"
+PORT=8000
+DATA_DIR="${HOME}/chongming-data"
+
+# 检查 docker
+if ! command -v docker &> /dev/null; then
+ log_error "Docker 未安装,请先安装 Docker"
+ exit 1
+fi
+
+# 检查镜像
+if ! docker image inspect "$IMAGE" &> /dev/null; then
+ log_error "镜像 $IMAGE 不存在,请先构建: docker build -t $IMAGE ."
+ exit 1
+fi
+
+# 1. 停止并删除旧容器
+if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then
+ log_warn "发现旧容器,正在停止并删除..."
+ docker stop "$CONTAINER" 2>/dev/null || true
+ docker rm "$CONTAINER" 2>/dev/null || true
+fi
+
+# 2. 创建目录
+log_info "创建数据目录..."
+mkdir -p "$DATA_DIR"/{data,uploads,logs}
+chmod 755 "$DATA_DIR"/{data,uploads,logs}
+
+# 3. 复制初始数据(仅在目录为空时)
+if [ -z "$(ls -A $DATA_DIR/data 2>/dev/null)" ]; then
+ log_info "首次部署,从镜像中提取初始数据库..."
+ TMP_CONTAINER="chongming-tmp-$$"
+ docker create --name "$TMP_CONTAINER" "$IMAGE" &> /dev/null
+ docker cp "$TMP_CONTAINER:/app/data/." "$DATA_DIR/data/" &> /dev/null
+ docker rm "$TMP_CONTAINER" &> /dev/null
+ log_info "初始数据库已就绪"
+else
+ log_info "数据库已存在,跳过初始化"
+fi
+
+# 检查端口是否被占用
+if ss -tlnp | grep -q ":${PORT}"; then
+ log_error "端口 ${PORT} 已被占用,请修改 PORT 变量或释放端口"
+ exit 1
+fi
+
+# 4. 启动容器
+log_info "启动容器..."
+docker run -d \
+ -p "$PORT:8000" \
+ -v "$DATA_DIR/data:/app/data" \
+ -v "$DATA_DIR/uploads:/app/uploads" \
+ -v "$DATA_DIR/logs:/app/logs" \
+ --restart unless-stopped \
+ --name "$CONTAINER" \
+ "$IMAGE"
+
+# 5. 等待启动
+log_info "等待应用启动..."
+sleep 3
+
+# 6. 检查状态
+if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER}$"; then
+ log_info "=========================================="
+ log_info "✅ 部署成功!"
+ log_info "=========================================="
+ log_info "应用地址: http://localhost:$PORT"
+ log_info "API 文档: http://localhost:$PORT/docs"
+ log_info "数据目录: $DATA_DIR"
+ log_info ""
+ log_info "查看日志: docker logs -f $CONTAINER"
+ log_info "停止服务: docker stop $CONTAINER"
+ log_info "重启服务: docker restart $CONTAINER"
+ log_info "=========================================="
+else
+ log_error "容器启动失败,查看日志:"
+ docker logs "$CONTAINER" 2>/dev/null || true
+ exit 1
+fi
\ No newline at end of file
diff --git a/dockerfile b/dockerfile
deleted file mode 100644
index e913144..0000000
--- a/dockerfile
+++ /dev/null
@@ -1,23 +0,0 @@
-# 使用 Debian 的极简版,确保有基础的 glibc(推荐)
-FROM debian:bookworm-slim
-
-# 可选:设置时区、安装 ca-certificates 等
-RUN apt-get update && apt-get install -y --no-install-recommends \
- ca-certificates \
- && rm -rf /var/lib/apt/lists/*
-
-WORKDIR /app
-
-# 复制打包好的可执行文件
-COPY build/chongming /app/
-
-# 复制运行时需要的静态资源、配置文件、.mbank 等
-COPY build/config.toml /app/
-COPY build/resources/ /app/resources/
-COPY build/static.svfs /app/
-
-# 暴露端口
-EXPOSE 8000
-
-# 启动
-CMD ["./chongming"]
\ No newline at end of file
diff --git a/public/config.toml b/public/config.toml
index 44eb5d2..3c5f5be 100644
--- a/public/config.toml
+++ b/public/config.toml
@@ -1,27 +1,27 @@
[default]
+app.debug = false
+app.description = "基于 FastAPI 的 chongming 打包脚手架"
app.name = "chongming"
app.version = "0.1.0"
-app.description = "基于 FastAPI 的 chongming 打包脚手架"
-app.debug = false
env = "production"
prefix = "/api/v1"
upload_path = "uploads"
[database]
-type = "sqlite"
-url = "sqlite+aiosqlite:///./database.db"
-generate_schemas = true # 生产环境使用迁移工具
+generate_schemas = true # 生产环境使用迁移工具
+type = "sqlite"
+url = "sqlite+aiosqlite:///./data/database.db"
[database.sqlite]
+connect_args.check_same_thread = false
+connect_args.timeout = 15
echo = false
echo_pool = false
-pool_size = 20
max_overflow = 10
-pool_timeout = 30
-pool_recycle = 300
pool_pre_ping = true
-connect_args.timeout = 15
-connect_args.check_same_thread = false
+pool_recycle = 300
+pool_size = 20
+pool_timeout = 30
[scheduler]
job_store_path = "scheduler_jobs.db"
@@ -30,62 +30,62 @@ job_store_path = "scheduler_jobs.db"
cache_store_path = "./"
[security]
-secret_key = "your-secret-key-change-in-production"
-algorithm = "HS256"
access_token_expire_minutes = 30
-refresh_token_expire_days = 7
+algorithm = "HS256"
max_sessions_per_user = 5
+refresh_token_expire_days = 7
+secret_key = "your-secret-key-change-in-production"
[development]
-env = "development"
debug = true
+env = "development"
[development.server]
+access_log = false
host = "127.0.0.1"
port = 8001
reload = true
-access_log = false
[development.logging]
-level = "DEBUG"
file = "logs"
format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+level = "DEBUG"
[development.cors]
-allow_origins = ["*"]
allow_credentials = true
-allow_methods = ["*"]
allow_headers = ["*"]
+allow_methods = ["*"]
+allow_origins = ["*"]
[production]
-env = "production"
debug = false
+env = "production"
[production.server]
+access_log = false
host = "0.0.0.0"
port = 8000
reload = false
-workers = 4
-access_log = false
timeout_keep_alive = 65
+workers = 4
[production.logging]
-level = "INFO"
-file = "logs"
-format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
-max_size = 10485760 # 10MB
-backup_count = 5 # 最多保存 10 个日志文件
+backup_count = 5 # 最多保存 10 个日志文件
+file = "logs"
+format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+level = "INFO"
+max_size = 10485760 # 10MB
[production.cors]
-allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
allow_credentials = true
-allow_methods = ["GET", "POST", "PUT", "DELETE"]
allow_headers = ["Authorization", "Content-Type"]
+allow_methods = ["GET", "POST", "PUT", "DELETE"]
+allow_origins = ["https://yourdomain.com", "http://localhost:8000", "http://127.0.0.1:8000"]
[production.module_system]
-type = "module-bank"
path = ["resources/app.mbank", "resources/plugins.mbank"]
+type = "module-bank"
[production.file_system]
-type = "svfs"
path = "static.svfs"
+type = "svfs"
diff --git a/src/chongming-web/public/favicon.ico b/src/chongming-web/public/favicon.ico
index df36fcf..79a6135 100644
Binary files a/src/chongming-web/public/favicon.ico and b/src/chongming-web/public/favicon.ico differ
diff --git a/src/chongming-web/src/assets/chongming64x64.png b/src/chongming-web/src/assets/chongming64x64.png
new file mode 100644
index 0000000..827ca41
Binary files /dev/null and b/src/chongming-web/src/assets/chongming64x64.png differ
diff --git a/src/chongming-web/src/assets/logo.png b/src/chongming-web/src/assets/logo.png
new file mode 100644
index 0000000..12c681f
Binary files /dev/null and b/src/chongming-web/src/assets/logo.png differ
diff --git a/src/chongming-web/src/assets/logo.svg b/src/chongming-web/src/assets/logo.svg
index 7565660..267be7e 100644
--- a/src/chongming-web/src/assets/logo.svg
+++ b/src/chongming-web/src/assets/logo.svg
@@ -1 +1,175 @@
-
+
+
+
diff --git a/src/chongming-web/src/main.ts b/src/chongming-web/src/main.ts
index ee64a16..a628d07 100644
--- a/src/chongming-web/src/main.ts
+++ b/src/chongming-web/src/main.ts
@@ -14,10 +14,10 @@ import { useAuthStore } from './stores/auth'
/**
* 打包时取消该注释
*/
-import { client } from "./api/generated/client.gen"
-client.setConfig({
- baseUrl: "/"
-})
+// import { client } from "./api/generated/client.gen"
+// client.setConfig({
+// baseUrl: "/"
+// })
const app = createApp(App)
diff --git a/src/chongming-web/src/stores/counter.ts b/src/chongming-web/src/stores/counter.ts
deleted file mode 100644
index b6757ba..0000000
--- a/src/chongming-web/src/stores/counter.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { ref, computed } from 'vue'
-import { defineStore } from 'pinia'
-
-export const useCounterStore = defineStore('counter', () => {
- const count = ref(0)
- const doubleCount = computed(() => count.value * 2)
- function increment() {
- count.value++
- }
-
- return { count, doubleCount, increment }
-})
diff --git a/src/chongming/app/__init__.py b/src/chongming/app/__init__.py
index 298e548..57250b9 100644
--- a/src/chongming/app/__init__.py
+++ b/src/chongming/app/__init__.py
@@ -64,8 +64,12 @@ async def lifespan(app: FastAPI):
database_config = database.get(database_type, None)
if database_config is None:
raise ValueError("配置不存在")
+ database_path = database.get("database_path", None)
+ if database_path:
+ Path(database_path).parent.mkdir(parents=True, exist_ok=True)
+ engine_config = {k: v for k, v in database_config.items() if k != "database_path"}
- engine = create_async_engine(database["url"], **database_config)
+ engine = create_async_engine(database["url"], **engine_config)
async_session_maker = async_sessionmaker(
engine, class_=AsyncSession, expire_on_commit=False
)
diff --git a/src/chongming/app/core/config.py b/src/chongming/app/core/config.py
index ff4aaad..52be9cf 100644
--- a/src/chongming/app/core/config.py
+++ b/src/chongming/app/core/config.py
@@ -60,6 +60,7 @@ class Database(TypedDict, total=False):
sqlite: DatabaseSqlite
mysql: dict
postgresql: dict
+ database_path: str
class Security(TypedDict):
diff --git a/src/chongming/scripts/build.py b/src/chongming/scripts/build.py
index c0f43cb..d25d26d 100644
--- a/src/chongming/scripts/build.py
+++ b/src/chongming/scripts/build.py
@@ -134,6 +134,10 @@ def run_pyinstaller():
"-m",
"PyInstaller",
"--onefile",
+ "--noconfirm",
+ "--optimize",
+ "2",
+ "--strip",
"--name",
"chongming",
"--distpath",
@@ -173,11 +177,7 @@ def run_pyinstaller():
"--hidden-import",
"diskcache",
"--hidden-import",
- "passlib",
- "--hidden-import",
- "passlib.context",
- "--hidden-import",
- "passlib.handlers.bcrypt",
+ "bcrypt",
"--hidden-import",
"sqlite_vfs",
"--hidden-import",
@@ -197,6 +197,10 @@ def run_pyinstaller():
"-m",
"PyInstaller",
"--onefile",
+ "--noconfirm",
+ "--optimize",
+ "2",
+ "--strip",
"--name",
"chongming",
"--distpath",
@@ -236,11 +240,7 @@ def run_pyinstaller():
"--hidden-import",
"diskcache",
"--hidden-import",
- "passlib",
- "--hidden-import",
- "passlib.context",
- "--hidden-import",
- "passlib.handlers.bcrypt",
+ "bcrypt",
"--hidden-import",
"sqlite_vfs",
"--hidden-import",
@@ -309,9 +309,9 @@ async def init_database():
database_config = database.get(database_type, None)
if database_config is None:
raise ValueError("配置不存在")
-
+ os.makedirs("./build/data", exist_ok=True)
engine = create_async_engine(
- "sqlite+aiosqlite:///./build/database.db", **database_config
+ "sqlite+aiosqlite:///./build/data/database.db", **database_config
)
async_session_maker = async_sessionmaker(
engine, class_=AsyncSession, expire_on_commit=False
diff --git a/src/chongming/scripts/code_content.py b/src/chongming/scripts/code_content.py
index 293add0..164f79d 100644
--- a/src/chongming/scripts/code_content.py
+++ b/src/chongming/scripts/code_content.py
@@ -22,7 +22,8 @@ def generate_markdown_from_py_files(directory, output_file):
or file.endswith(".ts")
or file.endswith(".json")
or file.endswith(".html")
- or file == "dockerfile"
+ or file.endswith(".sh")
+ or file == "Dockerfile"
):
file_path = os.path.join(root, file)
if file == "output.md" or file == "package-lock.json":