96 lines
2.9 KiB
Python
96 lines
2.9 KiB
Python
import os
|
|
from pathlib import Path
|
|
from typing import List
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
from backend.app.routers import (
|
|
customers,
|
|
projects,
|
|
finance,
|
|
settings,
|
|
ai_settings,
|
|
email_configs,
|
|
cloud_docs,
|
|
cloud_doc_config,
|
|
portal_links,
|
|
)
|
|
from backend.app.db import Base, engine
|
|
from backend.app import models # noqa: F401 - ensure models are imported
|
|
|
|
|
|
def create_app() -> FastAPI:
|
|
app = FastAPI(
|
|
title="Ops-Core",
|
|
description="Monolithic automation & business ops platform",
|
|
version="0.1.0",
|
|
)
|
|
|
|
# Ensure database tables exist (especially when running in Docker)
|
|
@app.on_event("startup")
|
|
def on_startup() -> None:
|
|
Base.metadata.create_all(bind=engine)
|
|
# Add new columns to finance_records if they don't exist (Module 6)
|
|
try:
|
|
from sqlalchemy import text
|
|
with engine.connect() as conn:
|
|
r = conn.execute(text("PRAGMA table_info(finance_records)"))
|
|
cols = [row[1] for row in r]
|
|
if "amount" not in cols:
|
|
conn.execute(text("ALTER TABLE finance_records ADD COLUMN amount NUMERIC(12,2)"))
|
|
if "billing_date" not in cols:
|
|
conn.execute(text("ALTER TABLE finance_records ADD COLUMN billing_date DATE"))
|
|
conn.commit()
|
|
except Exception:
|
|
pass
|
|
# Add customers.tags if missing (customer tags for project 收纳)
|
|
try:
|
|
from sqlalchemy import text
|
|
with engine.connect() as conn:
|
|
r = conn.execute(text("PRAGMA table_info(customers)"))
|
|
cols = [row[1] for row in r]
|
|
if "tags" not in cols:
|
|
conn.execute(text("ALTER TABLE customers ADD COLUMN tags VARCHAR(512)"))
|
|
conn.commit()
|
|
except Exception:
|
|
pass
|
|
|
|
# CORS
|
|
raw_origins = os.getenv("CORS_ORIGINS")
|
|
if raw_origins:
|
|
origins: List[str] = [o.strip() for o in raw_origins.split(",") if o.strip()]
|
|
else:
|
|
origins = ["*"]
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=origins,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# Routers
|
|
app.include_router(customers.router)
|
|
app.include_router(projects.router)
|
|
app.include_router(finance.router)
|
|
app.include_router(settings.router)
|
|
app.include_router(ai_settings.router)
|
|
app.include_router(email_configs.router)
|
|
app.include_router(cloud_docs.router)
|
|
app.include_router(cloud_doc_config.router)
|
|
app.include_router(portal_links.router)
|
|
|
|
# Static data mount (for quotes, contracts, finance archives, etc.)
|
|
data_dir = Path("data")
|
|
data_dir.mkdir(parents=True, exist_ok=True)
|
|
app.mount("/data", StaticFiles(directory=str(data_dir)), name="data")
|
|
|
|
return app
|
|
|
|
|
|
app = create_app()
|
|
|