- 后端: FastAPI + SQLAlchemy + SQLite, JWT认证, 代理支持的AirwallexClient - 前端: React 18 + Vite + Ant Design 5, 中文界面 - 功能: 卡片管理, 持卡人管理, 交易记录, API令牌, 系统设置, 审计日志 - 第三方API: X-API-Key认证, 权限控制 - Docker部署: docker-compose编排前后端
106 lines
3.3 KiB
Python
106 lines
3.3 KiB
Python
"""FastAPI application entry point."""
|
|
import logging
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
from .auth import get_password_hash
|
|
from .config import settings
|
|
from .database import SessionLocal, create_tables
|
|
from .models.db_models import SystemSetting
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
|
def _init_admin_and_defaults() -> None:
|
|
"""Initialize admin password hash and default settings."""
|
|
db = SessionLocal()
|
|
try:
|
|
# Store admin password hash
|
|
existing = (
|
|
db.query(SystemSetting)
|
|
.filter(SystemSetting.key == "admin_password_hash")
|
|
.first()
|
|
)
|
|
if not existing:
|
|
hashed = get_password_hash(settings.ADMIN_PASSWORD)
|
|
db.add(SystemSetting(key="admin_password_hash", value=hashed, encrypted=True))
|
|
logger.info("Admin user initialized.")
|
|
|
|
# Store Airwallex credentials from env if provided
|
|
for key, env_val in [
|
|
("airwallex_client_id", settings.AIRWALLEX_CLIENT_ID),
|
|
("airwallex_api_key", settings.AIRWALLEX_API_KEY),
|
|
("airwallex_base_url", settings.AIRWALLEX_BASE_URL),
|
|
]:
|
|
if env_val:
|
|
s = db.query(SystemSetting).filter(SystemSetting.key == key).first()
|
|
if not s:
|
|
db.add(SystemSetting(key=key, value=env_val, encrypted=(key == "airwallex_api_key")))
|
|
|
|
# Default daily card limit
|
|
if not db.query(SystemSetting).filter(SystemSetting.key == "daily_card_limit").first():
|
|
db.add(SystemSetting(key="daily_card_limit", value="100"))
|
|
|
|
db.commit()
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""Startup and shutdown logic."""
|
|
create_tables()
|
|
_init_admin_and_defaults()
|
|
logger.info("Application started.")
|
|
yield
|
|
logger.info("Application shutting down.")
|
|
|
|
|
|
app = FastAPI(
|
|
title="Airwallex Card Management",
|
|
version="1.0.0",
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
# CORS - allow all origins for development
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"],
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
|
|
# --- Mount routers (each router defines its own prefix) ---
|
|
from .routers import auth as auth_router
|
|
from .routers import cards as cards_router
|
|
from .routers import cardholders as cardholders_router
|
|
from .routers import dashboard as dashboard_router
|
|
from .routers import settings as settings_router
|
|
from .routers import logs as logs_router
|
|
from .routers import tokens as tokens_router
|
|
from .routers import transactions as transactions_router
|
|
from .routers import external_api as external_api_router
|
|
|
|
app.include_router(auth_router.router)
|
|
app.include_router(dashboard_router.router)
|
|
app.include_router(cards_router.router)
|
|
app.include_router(cardholders_router.router)
|
|
app.include_router(transactions_router.router)
|
|
app.include_router(settings_router.router)
|
|
app.include_router(tokens_router.router)
|
|
app.include_router(logs_router.router)
|
|
app.include_router(external_api_router.router)
|
|
|
|
|
|
# --- Health check ---
|
|
@app.get("/api/health")
|
|
async def health_check():
|
|
"""Simple health check endpoint."""
|
|
return {"status": "ok"}
|