chore: P1 工程化工具链

- pyproject.toml:pytest/black/isort/mypy 统一配置
- requirements-dev.txt:测试与代码规范开发依赖
- .flake8 / .editorconfig:PEP8 与编辑器统一
- .pre-commit-config.yaml:提交前钩子
- Makefile:常用命令集
- .env.example:环境变量模板(76 键)
- tests/:pytest 骨架 + R 响应格式冒烟测试

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
DjangoAdmin Dev
2026-08-07 12:14:51 +08:00
co-authored by Claude
parent 15f2a5e097
commit 8691412ec6
12 changed files with 448 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
# ============================================================
# DjangoAdmin Flask+EleVue 环境变量模板
# ============================================================
# 使用方法:
# 1. 复制为 .env:cp .env.example .env
# 2. 填写 <占位符> 标记的敏感值(严禁将真实 .env 提交到版本库)
# 说明:.env 已被 .gitignore 忽略
# ============================================================
# ============================================================
# 应用基础配置(config/app.py)
# ============================================================
FLASK_NAME=Flask+EleVue旗舰版
FLASK_VERSION=v2.8.0
FLASK_APP=app.py
FLASK_ENV=development # development / production
FLASK_DEBUG=True # 生产环境必须为 False
FLASK_USE_RELOADER=False
FLASK_HOST=127.0.0.1
FLASK_PORT=8021
FLASK_SECRET_KEY=<必填,长度至少16字符,如生成随机串>
FLASK_DEMO=False # True=演示模式,拦截写操作
# 站点域名(定时任务等内部 HTTP 调用使用)
# FLASK_SITE_DOMAIN=http://127.0.0.1:8021
# 跨域白名单(多个用英文逗号分隔;配置后 CORS 允许携带凭证)
CORS_ALLOWED_ORIGINS=http://localhost:8001
# 上传配置
FLASK_UPLOAD_DIR=./uploads
FLASK_FILE_URL=http://images.flask.elevue
UPLOAD_ALLOWED_EXTS=.jpg,.jpeg,.png,.gif,.bmp,.webp,.svg,.ico,.txt,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4,.zip,.rar,.7z
UPLOAD_MAX_SIZE_MB=10
# 反向代理层数(0=无代理;1=前面有 1 层 Nginx)
PROXY_NUM=0
# ============================================================
# 数据库配置(config/database.py)
# ============================================================
DB_DRIVER=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=djangoadmin.flask.elevue
DB_USERNAME=root
DB_PASSWORD=<必填>
DB_PREFIX=flask_
DB_DEBUG=True
DB_SSL=False
# 若开启 DB_SSL=True,配置以下证书路径
# DB_SSL_CA=
# DB_SSL_CERT=
# DB_SSL_KEY=
# ============================================================
# Redis 缓存(config/redis.py)
# ============================================================
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=<如有则填写,否则留空>
REDIS_INDEX=0
REDIS_AUTH=True # 是否启用密码认证
REDIS_DECODE_RESPONSES=True
# ============================================================
# JWT / 权限 / 白名单(config/auth.py)
# ============================================================
JWT_SALT=<必填,JWT 签名密钥,建议随机长串>
JWT_EXPIRE_MINUTES=20
LOGIN_FAIL_MAX=5
LOGIN_LOCK_SECONDS=300
PERMISSION_ENABLED=True # 权限校验总开关(开发可关)
# 内部调用密钥(定时任务等无用户场景,通过 X-Scheduler-Key / X-Internal-API-Key 传递)
INTERNAL_API_KEY=<必填>
INTERNAL_ALLOWED_IPS=127.0.0.1
# 登录白名单(以下路径跳过登录校验)
LOGIN_WHITELIST_EXACT=/login,/captcha,/favicon.ico
LOGIN_WHITELIST_PREFIX=/job/sendSms,/public,/static,/api/webhook
LOGIN_WHITELIST_WILDCARD=/job/*/send*,/api/v1/*/public*
LOGIN_WHITELIST_DEBUG=True
LOGIN_WHITELIST_LOG_ACCESS=True
# 验证码万能码(仅 FLASK_DEMO=True 时生效)
CAPTCHA_BYPASS_CODE=
# ============================================================
# 邮件(config/mail.py)
# ============================================================
MAIL_MAILER=smtp
MAIL_SERVER=smtp.163.com
MAIL_PORT=465
MAIL_USE_SSL=True
MAIL_ENCRYPTION=
MAIL_USERNAME=<必填>
MAIL_PASSWORD=<必填>
MAIL_FROM_NAME=
MAIL_FROM_ADDRESS=
# ============================================================
# 短信(config/sms.py,阿里云短信)
# ============================================================
SMS_PROVIDER=aliyun
SMS_ALIYUN_ACCESS_KEY_ID=<必填>
SMS_ALIYUN_ACCESS_KEY_SECRET=<必填>
SMS_ALIYUN_SIGN_NAME=<必填>
SMS_ALIYUN_ENDPOINT=dysmsapi.aliyuncs.com
SMS_ALIYUN_CONNECT_TIMEOUT=10000
SMS_ALIYUN_READ_TIMEOUT=10000
# ============================================================
# 验证码图片(config/captcha.py)
# ============================================================
CAPTCHA_LENGTH=6
CAPTCHA_EXPIRE=300
CAPTCHA_RATE_LIMIT=10
CAPTCHA_RATE_WINDOW=60
CAPTCHA_CHARS=ABCDEFGHJKLMNPQRSTUVWXYZ2346789
CAPTCHA_FONT_PATH=static/fonts/Vera.ttf
CAPTCHA_IMAGE_WIDTH=160
CAPTCHA_IMAGE_HEIGHT=50
CAPTCHA_FONT_SIZE=28
CAPTCHA_NOISE_LINES=6
CAPTCHA_NOISE_DOTS=30