feat: multi-user SaaS, piani Freemium/Pro, Google OAuth, admin panel
BLOCCO 1 - Multi-user data model: - User: email, display_name, avatar_url, auth_provider, google_id - User: subscription_plan, subscription_expires_at, is_admin, post counters - SubscriptionCode table per redeem codes - user_id FK su Character, Post, AffiliateLink, EditorialPlan, SocialAccount, SystemSetting - Migrazione SQLite-safe (ALTER TABLE) + preserva dati esistenti BLOCCO 2 - Auth completo: - Registrazione email/password + login multi-user - Google OAuth 2.0 (httpx, no deps esterne) - Callback flow: Google -> /auth/callback?token=JWT -> frontend - Backward compat login admin con username BLOCCO 3 - Piani e abbonamenti: - Freemium: 1 character, 15 post/mese, FB+IG only, no auto-plans - Pro: illimitato, tutte le piattaforme, tutte le feature - Enforcement automatico in tutti i router - Redeem codes con durate 1/3/6/12 mesi - Admin panel: genera codici, lista utenti BLOCCO 4 - Frontend completo: - Login page design Leopost (split coral/cream, Google, social coming soon) - AuthCallback per OAuth redirect - PlanBanner, UpgradeModal con pricing - AdminSettings per generazione codici - CharacterForm con tab Account Social + guide setup Deploy: - Dockerfile con ARG VITE_BASE_PATH/VITE_API_BASE - docker-compose.prod.yml per leopost.it (no subpath) - docker-compose.yml aggiornato per lab Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,10 +16,11 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
|
||||
from .auth import hash_password
|
||||
from .auth import router as auth_router
|
||||
from .config import settings
|
||||
from .database import Base, SessionLocal, engine
|
||||
from .database import Base, SessionLocal, engine, run_migrations
|
||||
from .models import User
|
||||
from .routers.admin import router as admin_router
|
||||
from .routers.auth import router as auth_router
|
||||
from .routers.affiliates import router as affiliates_router
|
||||
from .routers.characters import router as characters_router
|
||||
from .routers.comments import router as comments_router
|
||||
@@ -78,10 +79,13 @@ async def lifespan(app: FastAPI):
|
||||
data_dir = Path("./data")
|
||||
data_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create tables
|
||||
# Run migrations FIRST (add new columns to existing tables)
|
||||
run_migrations(engine)
|
||||
|
||||
# Create tables (for new tables like subscription_codes)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
# Create admin user if not exists
|
||||
# Create or update admin user
|
||||
db = SessionLocal()
|
||||
try:
|
||||
existing = db.query(User).filter(User.username == settings.admin_username).first()
|
||||
@@ -89,9 +93,28 @@ async def lifespan(app: FastAPI):
|
||||
admin = User(
|
||||
username=settings.admin_username,
|
||||
hashed_password=hash_password(settings.admin_password),
|
||||
email="admin@leopost.it",
|
||||
display_name="Admin",
|
||||
auth_provider="local",
|
||||
subscription_plan="pro",
|
||||
is_admin=True,
|
||||
)
|
||||
db.add(admin)
|
||||
db.commit()
|
||||
else:
|
||||
# Update existing admin to ensure proper flags
|
||||
updated = False
|
||||
if not existing.is_admin:
|
||||
existing.is_admin = True
|
||||
updated = True
|
||||
if existing.subscription_plan != "pro":
|
||||
existing.subscription_plan = "pro"
|
||||
updated = True
|
||||
if not existing.email:
|
||||
existing.email = "admin@leopost.it"
|
||||
updated = True
|
||||
if updated:
|
||||
db.commit()
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@@ -114,13 +137,17 @@ async def lifespan(app: FastAPI):
|
||||
# CRITICAL: Do NOT pass root_path here — use Uvicorn --root-path instead.
|
||||
app = FastAPI(
|
||||
title="Leopost Full",
|
||||
version="0.1.0",
|
||||
version="0.2.0",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://localhost:5173"],
|
||||
allow_origins=[
|
||||
"http://localhost:5173",
|
||||
"https://leopost.it",
|
||||
"https://www.leopost.it",
|
||||
],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
@@ -131,6 +158,7 @@ app.add_middleware(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
app.include_router(auth_router)
|
||||
app.include_router(admin_router)
|
||||
app.include_router(characters_router)
|
||||
app.include_router(content_router)
|
||||
app.include_router(affiliates_router)
|
||||
@@ -143,7 +171,7 @@ app.include_router(editorial_router)
|
||||
|
||||
@app.get("/api/health")
|
||||
def health():
|
||||
return {"status": "ok", "version": "0.1.0"}
|
||||
return {"status": "ok", "version": "0.2.0"}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user