docs: project docs, scripts, deployment configs, and evidence

This commit is contained in:
2026-04-02 11:22:17 +08:00
parent 4718980ab5
commit bbeeb63dfa
396 changed files with 165018 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
# Backup Restore Drill
- Generated at: 2026-03-24 07:23:14 +08:00
- Source DB: $SourceDb
- Backup DB: $backupDb
- Restored DB: $restoredDb
- Probe port: 18080
## Hash Validation
- source sha256: $sourceHash
- backup sha256: $backupHash
- restored sha256: $restoredHash
## Snapshot Comparison
- source tables: $sourceTablesJson
- restored tables: $restoredTablesJson
- source existing tables: $((devices login_logs operation_logs password_histories permissions role_permissions roles sqlite_sequence user_roles user_social_accounts users webhook_deliveries webhooks -join ', '))
- restored existing tables: $((devices login_logs operation_logs password_histories permissions role_permissions roles sqlite_sequence user_roles user_social_accounts users webhook_deliveries webhooks -join ', '))
- source missing tables: $(if (social_accounts.Count -gt 0) { social_accounts -join ', ' } else { 'none' })
- restored missing tables: $(if (social_accounts.Count -gt 0) { social_accounts -join ', ' } else { 'none' })
- sample users: $((@{generated_at=2026-03-24T07:23:07+08:00; path=D:\project\data\user_management.db; file_size=172032; existing_tables=System.Object[]; missing_tables=System.Object[]; tables=; sample_users=System.Object[]}.SampleUsers -join ', '))
## Restore Service Verification
- GET /health: pass
- GET /health/ready: pass
- GET /api/v1/auth/capabilities: pass
- auth capabilities payload: $((@{code=0; message=success; data=}.data | ConvertTo-Json -Compress))
## Evidence Files
- $(Split-Path D:\project\docs\evidence\ops\2026-03-24\backup-restore\20260324-072304\source-snapshot.json -Leaf)
- $(Split-Path D:\project\docs\evidence\ops\2026-03-24\backup-restore\20260324-072304\restored-snapshot.json -Leaf)
- $(Split-Path D:\project\docs\evidence\ops\2026-03-24\backup-restore\20260324-072304\server.stdout.log -Leaf)
- $(Split-Path D:\project\docs\evidence\ops\2026-03-24\backup-restore\20260324-072304\server.stderr.log -Leaf)
- $(Split-Path D:\project\docs\evidence\ops\2026-03-24\backup-restore\20260324-072304\config.restore.yaml -Leaf)

View File

@@ -0,0 +1,215 @@
server:
port: 18080
mode: release # debug, release
read_timeout: 30s
read_header_timeout: 10s
write_timeout: 30s
idle_timeout: 60s
shutdown_timeout: 15s
max_header_bytes: 1048576
database:
type: sqlite # sqlite, postgresql, mysql
sqlite:
path: "D:/project/docs/evidence/ops/2026-03-24/backup-restore/20260324-072304/user_management.restored.db"
postgresql:
host: localhost
port: 5432
database: user_management
username: postgres
password: password
ssl_mode: disable
max_open_conns: 100
max_idle_conns: 10
mysql:
host: localhost
port: 3306
database: user_management
username: root
password: password
charset: utf8mb4
max_open_conns: 100
max_idle_conns: 10
cache:
l1:
enabled: true
max_size: 10000
ttl: 5m
l2:
enabled: false
type: redis
redis:
addr: localhost:6379
password: ""
db: 0
pool_size: 50
ttl: 30m
redis:
enabled: false
addr: localhost:6379
password: ""
db: 0
jwt:
algorithm: RS256
secret: your-secret-key-change-in-production
private_key_path: "./data/jwt/private.pem"
public_key_path: "./data/jwt/public.pem"
private_key_pem: ""
public_key_pem: ""
access_token_expire: 2h
refresh_token_expire: 168h # 7澶?= 168灏忔椂
security:
password_min_length: 8
password_require_special: true
password_require_number: true
login_max_attempts: 5
login_lock_duration: 30m
ratelimit:
enabled: true
login:
enabled: true
algorithm: token_bucket
capacity: 5
rate: 1
window: 1m
register:
enabled: true
algorithm: leaky_bucket
capacity: 3
rate: 1
window: 1h
api:
enabled: true
algorithm: sliding_window
capacity: 1000
window: 1m
monitoring:
prometheus:
enabled: true
path: /metrics
tracing:
enabled: false
endpoint: http://localhost:4318
service_name: user-management-system
logging:
level: info # debug, info, warn, error
format: json # json, text
output:
- stdout
- ./logs/app.log
rotation:
max_size: 100 # MB
max_age: 30 # days
max_backups: 10
admin:
username: ""
password: ""
email: ""
cors:
enabled: true
allowed_origins:
- "http://localhost:3000"
- "http://127.0.0.1:3000"
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowed_headers:
- Authorization
- Content-Type
- X-Requested-With
- X-CSRF-Token
max_age: 3600
email:
host: "" # 鐢熶骇鐜濉啓鐪熷疄 SMTP Host
port: 18080
username: ""
password: ""
from_email: ""
from_name: "鐢ㄦ埛绠$悊绯荤粺"
sms:
enabled: false
provider: "" # aliyun, tencent锛涚暀绌鸿〃绀虹鐢ㄧ煭淇¤兘鍔? code_ttl: 5m
resend_cooldown: 1m
max_daily_limit: 10
aliyun:
access_key_id: ""
access_key_secret: ""
sign_name: ""
template_code: ""
endpoint: ""
region_id: "cn-hangzhou"
code_param_name: "code"
tencent:
secret_id: ""
secret_key: ""
app_id: ""
sign_name: ""
template_id: ""
region: "ap-guangzhou"
endpoint: ""
password_reset:
token_ttl: 15m
site_url: "http://localhost:8080"
# OAuth 绀句氦鐧诲綍閰嶇疆锛堢暀绌哄垯绂佺敤瀵瑰簲 Provider锛?
oauth:
google:
client_id: ""
client_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/google/callback"
wechat:
app_id: ""
app_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/wechat/callback"
github:
client_id: ""
client_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/github/callback"
qq:
app_id: ""
app_key: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/qq/callback"
alipay:
app_id: ""
private_key: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/alipay/callback"
sandbox: false
douyin:
client_key: ""
client_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/douyin/callback"
# Webhook 鍏ㄥ眬閰嶇疆
webhook:
enabled: true
secret_header: "X-Webhook-Signature" # 绛惧悕 Header 鍚嶇О
timeout_sec: 30 # 鍗曟鎶曢€掕秴鏃讹紙绉掞級
max_retries: 3 # 鏈€澶ч噸璇曟鏁?
retry_backoff: "exponential" # 閫€閬跨瓥鐣ワ細exponential / fixed
worker_count: 4 # 鍚庡彴鎶曢€掑崗绋嬫暟
queue_size: 1000 # 鎶曢€掗槦鍒楀ぇ灏?
# IP 瀹夊叏閰嶇疆
ip_security:
auto_block_enabled: true # 鏄惁鍚敤鑷姩灏佺
auto_block_duration: 30m # 鑷姩灏佺鏃堕暱
brute_force_threshold: 10 # 鏆村姏鐮磋В闃堝€硷紙绐楀彛鍐呭け璐ユ鏁帮級
detection_window: 15m # 妫€娴嬫椂闂寸獥鍙?

View File

@@ -0,0 +1,40 @@
{
"generated_at": "2026-03-24T07:23:08+08:00",
"path": "D:\\project\\docs\\evidence\\ops\\2026-03-24\\backup-restore\\20260324-072304\\user_management.restored.db",
"file_size": 172032,
"existing_tables": [
"devices",
"login_logs",
"operation_logs",
"password_histories",
"permissions",
"role_permissions",
"roles",
"sqlite_sequence",
"user_roles",
"user_social_accounts",
"users",
"webhook_deliveries",
"webhooks"
],
"missing_tables": [
"social_accounts"
],
"tables": {
"devices": 0,
"login_logs": 2,
"operation_logs": 6,
"password_histories": 0,
"permissions": 17,
"role_permissions": 20,
"roles": 2,
"user_roles": 1,
"users": 1,
"webhook_deliveries": 0,
"webhooks": 0
},
"sample_users": [
"e2e_admin"
]
}

View File

@@ -0,0 +1,40 @@
{
"generated_at": "2026-03-24T07:23:07+08:00",
"path": "D:\\project\\data\\user_management.db",
"file_size": 172032,
"existing_tables": [
"devices",
"login_logs",
"operation_logs",
"password_histories",
"permissions",
"role_permissions",
"roles",
"sqlite_sequence",
"user_roles",
"user_social_accounts",
"users",
"webhook_deliveries",
"webhooks"
],
"missing_tables": [
"social_accounts"
],
"tables": {
"devices": 0,
"login_logs": 2,
"operation_logs": 6,
"password_histories": 0,
"permissions": 17,
"role_permissions": 20,
"roles": 2,
"user_roles": 1,
"users": 1,
"webhook_deliveries": 0,
"webhooks": 0
},
"sample_users": [
"e2e_admin"
]
}

View File

@@ -0,0 +1,39 @@
# Backup Restore Drill
- Generated at: 2026-03-24 07:24:00 +08:00
- Source DB: D:\project\data\user_management.db
- Backup DB: D:\project\docs\evidence\ops\2026-03-24\backup-restore\20260324-072353\user_management.backup.db
- Restored DB: D:\project\docs\evidence\ops\2026-03-24\backup-restore\20260324-072353\user_management.restored.db
- Probe port: 18080
## Hash Validation
- source sha256: FFC7A3326BF4C57569FC0E5429206971E122846ADEF1DE167E1B81CED9D8E0F4
- backup sha256: FFC7A3326BF4C57569FC0E5429206971E122846ADEF1DE167E1B81CED9D8E0F4
- restored sha256: FFC7A3326BF4C57569FC0E5429206971E122846ADEF1DE167E1B81CED9D8E0F4
## Snapshot Comparison
- source tables: {"devices":0,"login_logs":2,"operation_logs":6,"password_histories":0,"permissions":17,"role_permissions":20,"roles":2,"user_roles":1,"users":1,"webhook_deliveries":0,"webhooks":0}
- restored tables: {"devices":0,"login_logs":2,"operation_logs":6,"password_histories":0,"permissions":17,"role_permissions":20,"roles":2,"user_roles":1,"users":1,"webhook_deliveries":0,"webhooks":0}
- source existing tables: devices, login_logs, operation_logs, password_histories, permissions, role_permissions, roles, sqlite_sequence, user_roles, user_social_accounts, users, webhook_deliveries, webhooks
- restored existing tables: devices, login_logs, operation_logs, password_histories, permissions, role_permissions, roles, sqlite_sequence, user_roles, user_social_accounts, users, webhook_deliveries, webhooks
- source missing tables: social_accounts
- restored missing tables: social_accounts
- sample users: e2e_admin
## Restore Service Verification
- GET /health: pass
- GET /health/ready: pass
- GET /api/v1/auth/capabilities: pass
- auth capabilities payload: {"password":true,"email_code":false,"sms_code":false,"password_reset":false,"oauth_providers":[]}
## Evidence Files
- source-snapshot.json
- restored-snapshot.json
- server.stdout.log
- server.stderr.log
- config.restore.yaml

View File

@@ -0,0 +1,215 @@
server:
port: 18080
mode: release # debug, release
read_timeout: 30s
read_header_timeout: 10s
write_timeout: 30s
idle_timeout: 60s
shutdown_timeout: 15s
max_header_bytes: 1048576
database:
type: sqlite # sqlite, postgresql, mysql
sqlite:
path: "D:/project/docs/evidence/ops/2026-03-24/backup-restore/20260324-072353/user_management.restored.db"
postgresql:
host: localhost
port: 5432
database: user_management
username: postgres
password: password
ssl_mode: disable
max_open_conns: 100
max_idle_conns: 10
mysql:
host: localhost
port: 3306
database: user_management
username: root
password: password
charset: utf8mb4
max_open_conns: 100
max_idle_conns: 10
cache:
l1:
enabled: true
max_size: 10000
ttl: 5m
l2:
enabled: false
type: redis
redis:
addr: localhost:6379
password: ""
db: 0
pool_size: 50
ttl: 30m
redis:
enabled: false
addr: localhost:6379
password: ""
db: 0
jwt:
algorithm: RS256
secret: your-secret-key-change-in-production
private_key_path: "./data/jwt/private.pem"
public_key_path: "./data/jwt/public.pem"
private_key_pem: ""
public_key_pem: ""
access_token_expire: 2h
refresh_token_expire: 168h # 7澶?= 168灏忔椂
security:
password_min_length: 8
password_require_special: true
password_require_number: true
login_max_attempts: 5
login_lock_duration: 30m
ratelimit:
enabled: true
login:
enabled: true
algorithm: token_bucket
capacity: 5
rate: 1
window: 1m
register:
enabled: true
algorithm: leaky_bucket
capacity: 3
rate: 1
window: 1h
api:
enabled: true
algorithm: sliding_window
capacity: 1000
window: 1m
monitoring:
prometheus:
enabled: true
path: /metrics
tracing:
enabled: false
endpoint: http://localhost:4318
service_name: user-management-system
logging:
level: info # debug, info, warn, error
format: json # json, text
output:
- stdout
- ./logs/app.log
rotation:
max_size: 100 # MB
max_age: 30 # days
max_backups: 10
admin:
username: ""
password: ""
email: ""
cors:
enabled: true
allowed_origins:
- "http://localhost:3000"
- "http://127.0.0.1:3000"
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
allowed_headers:
- Authorization
- Content-Type
- X-Requested-With
- X-CSRF-Token
max_age: 3600
email:
host: "" # 鐢熶骇鐜濉啓鐪熷疄 SMTP Host
port: 18080
username: ""
password: ""
from_email: ""
from_name: "鐢ㄦ埛绠$悊绯荤粺"
sms:
enabled: false
provider: "" # aliyun, tencent锛涚暀绌鸿〃绀虹鐢ㄧ煭淇¤兘鍔? code_ttl: 5m
resend_cooldown: 1m
max_daily_limit: 10
aliyun:
access_key_id: ""
access_key_secret: ""
sign_name: ""
template_code: ""
endpoint: ""
region_id: "cn-hangzhou"
code_param_name: "code"
tencent:
secret_id: ""
secret_key: ""
app_id: ""
sign_name: ""
template_id: ""
region: "ap-guangzhou"
endpoint: ""
password_reset:
token_ttl: 15m
site_url: "http://localhost:8080"
# OAuth 绀句氦鐧诲綍閰嶇疆锛堢暀绌哄垯绂佺敤瀵瑰簲 Provider锛?
oauth:
google:
client_id: ""
client_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/google/callback"
wechat:
app_id: ""
app_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/wechat/callback"
github:
client_id: ""
client_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/github/callback"
qq:
app_id: ""
app_key: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/qq/callback"
alipay:
app_id: ""
private_key: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/alipay/callback"
sandbox: false
douyin:
client_key: ""
client_secret: ""
redirect_url: "http://localhost:8080/api/v1/auth/oauth/douyin/callback"
# Webhook 鍏ㄥ眬閰嶇疆
webhook:
enabled: true
secret_header: "X-Webhook-Signature" # 绛惧悕 Header 鍚嶇О
timeout_sec: 30 # 鍗曟鎶曢€掕秴鏃讹紙绉掞級
max_retries: 3 # 鏈€澶ч噸璇曟鏁?
retry_backoff: "exponential" # 閫€閬跨瓥鐣ワ細exponential / fixed
worker_count: 4 # 鍚庡彴鎶曢€掑崗绋嬫暟
queue_size: 1000 # 鎶曢€掗槦鍒楀ぇ灏?
# IP 瀹夊叏閰嶇疆
ip_security:
auto_block_enabled: true # 鏄惁鍚敤鑷姩灏佺
auto_block_duration: 30m # 鑷姩灏佺鏃堕暱
brute_force_threshold: 10 # 鏆村姏鐮磋В闃堝€硷紙绐楀彛鍐呭け璐ユ鏁帮級
detection_window: 15m # 妫€娴嬫椂闂寸獥鍙?

View File

@@ -0,0 +1,40 @@
{
"generated_at": "2026-03-24T07:23:55+08:00",
"path": "D:\\project\\docs\\evidence\\ops\\2026-03-24\\backup-restore\\20260324-072353\\user_management.restored.db",
"file_size": 172032,
"existing_tables": [
"devices",
"login_logs",
"operation_logs",
"password_histories",
"permissions",
"role_permissions",
"roles",
"sqlite_sequence",
"user_roles",
"user_social_accounts",
"users",
"webhook_deliveries",
"webhooks"
],
"missing_tables": [
"social_accounts"
],
"tables": {
"devices": 0,
"login_logs": 2,
"operation_logs": 6,
"password_histories": 0,
"permissions": 17,
"role_permissions": 20,
"roles": 2,
"user_roles": 1,
"users": 1,
"webhook_deliveries": 0,
"webhooks": 0
},
"sample_users": [
"e2e_admin"
]
}

View File

@@ -0,0 +1,40 @@
{
"generated_at": "2026-03-24T07:23:54+08:00",
"path": "D:\\project\\data\\user_management.db",
"file_size": 172032,
"existing_tables": [
"devices",
"login_logs",
"operation_logs",
"password_histories",
"permissions",
"role_permissions",
"roles",
"sqlite_sequence",
"user_roles",
"user_social_accounts",
"users",
"webhook_deliveries",
"webhooks"
],
"missing_tables": [
"social_accounts"
],
"tables": {
"devices": 0,
"login_logs": 2,
"operation_logs": 6,
"password_histories": 0,
"permissions": 17,
"role_permissions": 20,
"roles": 2,
"user_roles": 1,
"users": 1,
"webhook_deliveries": 0,
"webhooks": 0
},
"sample_users": [
"e2e_admin"
]
}