Compare commits

...

2 Commits

16 changed files with 39 additions and 39 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from jose import JWTError
from backend.app.services.auth import decode_token
from .services.auth import decode_token
_bearer = HTTPBearer()
+6 -6
View File
@@ -1,9 +1,9 @@
from backend.app.routers import auth as auth_router
from backend.app.routers import users as users_router
from backend.app.routers import admin as admin_router
from backend.app.routers import ai as ai_router
from backend.app.routers import generate as generate_router
from backend.app.db import close_db, init_db
from .routers import auth as auth_router
from .routers import users as users_router
from .routers import admin as admin_router
from .routers import ai as ai_router
from .routers import generate as generate_router
from .db import close_db, init_db
import os
from contextlib import asynccontextmanager
+2 -2
View File
@@ -3,8 +3,8 @@ from datetime import datetime, timezone
from fastapi import APIRouter, Depends
from backend.app.db import get_conn, get_write_lock
from backend.app.dependencies import require_admin
from ..db import get_conn, get_write_lock
from ..dependencies import require_admin
router = APIRouter(prefix="/admin", tags=["admin"])
+3 -3
View File
@@ -1,9 +1,9 @@
"""AI router: model listing and chat completions via OpenRouter."""
from fastapi import APIRouter, Depends, HTTPException, status
from backend.app.dependencies import get_current_user
from backend.app.models.ai import ChatRequest, ChatResponse, ModelInfo
from backend.app.services import openrouter
from ..dependencies import get_current_user
from ..models.ai import ChatRequest, ChatResponse, ModelInfo
from ..services import openrouter
router = APIRouter(prefix="/ai", tags=["ai"])
+3 -3
View File
@@ -4,8 +4,8 @@ import uuid
from fastapi import APIRouter, HTTPException, status
from jose import JWTError
from backend.app.models.auth import LoginRequest, RefreshRequest, RegisterRequest, TokenResponse
from backend.app.services.auth import (
from ..models.auth import LoginRequest, RefreshRequest, RegisterRequest, TokenResponse
from ..services.auth import (
authenticate_user,
create_access_token,
create_refresh_token,
@@ -71,7 +71,7 @@ async def refresh(body: RefreshRequest) -> TokenResponse:
new_jti = str(uuid.uuid4())
await store_refresh_token(user_id, new_jti)
from backend.app.db import get_conn
from ..db import get_conn
conn = get_conn()
row = conn.execute(
"SELECT email, role FROM users WHERE id = ?", [user_id]
+3 -3
View File
@@ -1,8 +1,8 @@
"""Generate router: text, image, video, and image-to-video generation."""
from fastapi import APIRouter, Depends, HTTPException, status
from backend.app.dependencies import get_current_user
from backend.app.models.ai import (
from ..dependencies import get_current_user
from ..models.ai import (
ImageRequest,
ImageResponse,
ImageResult,
@@ -12,7 +12,7 @@ from backend.app.models.ai import (
VideoRequest,
VideoResponse,
)
from backend.app.services import openrouter
from ..services import openrouter
router = APIRouter(prefix="/generate", tags=["generate"])
+3 -3
View File
@@ -1,9 +1,9 @@
"""Users router: self-service profile and admin user management."""
from fastapi import APIRouter, Depends, HTTPException, status
from backend.app.dependencies import get_current_user, require_admin
from backend.app.models.users import SetRoleRequest, UpdateUserRequest, UserResponse
from backend.app.services.users import (
from ..dependencies import get_current_user, require_admin
from ..models.users import SetRoleRequest, UpdateUserRequest, UserResponse
from ..services.users import (
delete_user,
get_user,
list_users,
+1 -1
View File
@@ -6,7 +6,7 @@ from typing import Any
from jose import JWTError, jwt
from passlib.context import CryptContext
from backend.app.db import get_conn, get_write_lock
from ..db import get_conn, get_write_lock
_pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
+2 -2
View File
@@ -1,8 +1,8 @@
"""User management service: CRUD helpers against DuckDB."""
from typing import Any
from backend.app.db import get_conn, get_write_lock
from backend.app.services.auth import hash_password
from ..db import get_conn, get_write_lock
from .auth import hash_password
async def get_user(user_id: str) -> dict[str, Any] | None:
+2 -2
View File
@@ -4,8 +4,8 @@ import pytest
import pytest_asyncio
from httpx import AsyncClient, ASGITransport
from backend.app.main import app
from backend.app import db as db_module
from app.main import app
from app import db as db_module
os.environ.setdefault("JWT_SECRET", "test-secret-key-for-testing-only")
+2 -2
View File
@@ -5,8 +5,8 @@ import pytest_asyncio
from unittest.mock import AsyncMock, patch
from httpx import AsyncClient, ASGITransport
from backend.app.main import app
from backend.app import db as db_module
from app.main import app
from app import db as db_module
os.environ.setdefault("JWT_SECRET", "test-secret-key-for-testing-only")
os.environ.setdefault("OPENROUTER_API_KEY", "test-key")
+2 -2
View File
@@ -1,6 +1,6 @@
"""Integration tests for auth endpoints using in-memory DuckDB."""
from backend.app.main import app
from backend.app import db as db_module
from app.main import app
from app import db as db_module
from httpx import AsyncClient, ASGITransport
import os
import pytest
+1 -1
View File
@@ -3,7 +3,7 @@ import asyncio
import pytest
import duckdb
from backend.app import db as db_module
from app import db as db_module
@pytest.fixture(autouse=True)
+2 -2
View File
@@ -5,8 +5,8 @@ import pytest_asyncio
from unittest.mock import AsyncMock, patch
from httpx import AsyncClient, ASGITransport
from backend.app.main import app
from backend.app import db as db_module
from app.main import app
from app import db as db_module
os.environ.setdefault("JWT_SECRET", "test-secret-key-for-testing-only")
os.environ.setdefault("OPENROUTER_API_KEY", "test-key")
+2 -2
View File
@@ -4,8 +4,8 @@ import pytest
import pytest_asyncio
from httpx import AsyncClient, ASGITransport
from backend.app.main import app
from backend.app import db as db_module
from app.main import app
from app import db as db_module
os.environ.setdefault("JWT_SECRET", "test-secret-key-for-testing-only")
+4 -4
View File
@@ -33,11 +33,11 @@ Coolify's built-in reverse proxy routes traffic:
7. Set **Ports Exposed** to `8000`
8. Set **Start Command** to:
```txt
uvicorn backend.app.main:app --host 0.0.0.0 --port 8000
uvicorn app.main:app --host 0.0.0.0 --port 8000
```
9. Click **Create Resource**
> **Note:** Nixpacks auto-detects Python from `requirements.txt`. No `nixpacks.toml` file is needed. The Base Directory setting is the key configuration — without it, Nixpacks looks at the repository root and won't find the Python project.
> **Important:** Nixpacks copies the **contents** of the Base Directory to `/app/` in the container. When Base Directory is `/backend`, the `backend/` folder wrapper is removed — only `app/`, `tests/`, and `requirements.txt` are copied. Therefore the start command uses `app.main:app` (not `backend.app.main:app`).
### Backend Environment Variables
@@ -61,11 +61,11 @@ Add these as **Runtime** environment variables in Coolify:
6. Set **Ports Exposed** to `5000`
7. Set **Start Command** to:
```txt
gunicorn frontend.app.main:app --bind 0.0.0.0:5000 --workers 2 --timeout 120
gunicorn app.main:app --bind 0.0.0.0:5000 --workers 2 --timeout 120
```
8. Click **Create Resource**
> **Note:** Nixpacks auto-detects Python from `requirements.txt`. No `nixpacks.toml` file is needed. The Base Directory setting is the key configuration — without it, Nixpacks looks at the repository root and won't find the Python project.
> **Important:** Nixpacks copies the **contents** of the Base Directory to `/app/` in the container. When Base Directory is `/frontend`, the `frontend/` folder wrapper is removed — only `app/`, `tests/`, and `requirements.txt` are copied. Therefore the start command uses `app.main:app` (not `frontend.app.main:app`).
### Frontend Environment Variables