mirror of
https://github.com/aljazceru/enclava.git
synced 2025-12-17 07:24:34 +01:00
cleaup env
This commit is contained in:
50
.env.example
50
.env.example
@@ -1,9 +1,19 @@
|
|||||||
# ===================================
|
# ===================================
|
||||||
# ENCLAVA MINIMAL CONFIGURATION
|
# ENCLAVA CONFIGURATION
|
||||||
# ===================================
|
# ===================================
|
||||||
# Only essential environment variables that CANNOT have defaults
|
# Only essential environment variables that CANNOT have defaults
|
||||||
# Other settings should be configurable through the app UI
|
# Other settings should be configurable through the app UI
|
||||||
|
|
||||||
|
# Admin user (created on first startup only)
|
||||||
|
ADMIN_EMAIL=admin@example.com
|
||||||
|
ADMIN_PASSWORD=admin123
|
||||||
|
|
||||||
|
|
||||||
|
# ===================================
|
||||||
|
# APPLICATION BASE URL (Required - derives all URLs and CORS)
|
||||||
|
# ===================================
|
||||||
|
BASE_URL=localhost
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# INFRASTRUCTURE (Required)
|
# INFRASTRUCTURE (Required)
|
||||||
# ===================================
|
# ===================================
|
||||||
@@ -18,9 +28,7 @@ POSTGRES_PASSWORD=enclava_pass
|
|||||||
JWT_SECRET=your-super-secret-jwt-key-here-change-in-production
|
JWT_SECRET=your-super-secret-jwt-key-here-change-in-production
|
||||||
PRIVATEMODE_API_KEY=your-privatemode-api-key-here
|
PRIVATEMODE_API_KEY=your-privatemode-api-key-here
|
||||||
|
|
||||||
# Admin user (created on first startup only)
|
|
||||||
ADMIN_EMAIL=admin@example.com
|
|
||||||
ADMIN_PASSWORD=admin123
|
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# ADDITIONAL SECURITY SETTINGS (Optional but recommended)
|
# ADDITIONAL SECURITY SETTINGS (Optional but recommended)
|
||||||
@@ -36,29 +44,31 @@ ADMIN_PASSWORD=admin123
|
|||||||
# API Key prefix (default: en_)
|
# API Key prefix (default: en_)
|
||||||
# API_KEY_PREFIX=en_
|
# API_KEY_PREFIX=en_
|
||||||
|
|
||||||
# Security thresholds (0.0-1.0)
|
|
||||||
# API_SECURITY_RISK_THRESHOLD=0.8
|
|
||||||
# API_SECURITY_WARNING_THRESHOLD=0.6
|
|
||||||
# API_SECURITY_ANOMALY_THRESHOLD=0.7
|
|
||||||
|
|
||||||
# IP security (comma-separated for multiple IPs)
|
|
||||||
# API_BLOCKED_IPS=
|
|
||||||
# API_ALLOWED_IPS=
|
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# APPLICATION BASE URL (Required - derives all URLs and CORS)
|
# FRONTEND ENVIRONMENT (Required for production)
|
||||||
# ===================================
|
# ===================================
|
||||||
BASE_URL=localhost
|
NODE_ENV=production
|
||||||
# Frontend derives: APP_URL=http://localhost, API_URL=http://localhost, WS_URL=ws://localhost
|
NEXT_PUBLIC_APP_NAME=Enclava
|
||||||
# Backend derives: CORS_ORIGINS=["http://localhost"]
|
# NEXT_PUBLIC_BASE_URL is derived from BASE_URL in Docker configuration
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# DOCKER NETWORKING (Required for containers)
|
# LOGGING CONFIGURATION
|
||||||
# ===================================
|
# ===================================
|
||||||
BACKEND_INTERNAL_PORT=8000
|
LOG_LLM_PROMPTS=false
|
||||||
FRONTEND_INTERNAL_PORT=3000
|
|
||||||
# Hosts are fixed: enclava-backend, enclava-frontend
|
# For production HTTPS deployments, set:
|
||||||
# Upstreams derive: enclava-backend:8000, enclava-frontend:3000
|
# BASE_URL=your-domain.com
|
||||||
|
# The system will automatically detect HTTPS and use it for all URLs and CORS
|
||||||
|
|
||||||
|
# ===================================
|
||||||
|
# DOCKER NETWORKING (Optional - defaults provided)
|
||||||
|
# ===================================
|
||||||
|
# Internal ports use defaults: backend=8000, frontend=3000
|
||||||
|
# Override only if you need to change these defaults:
|
||||||
|
# BACKEND_INTERNAL_PORT=8000
|
||||||
|
# FRONTEND_INTERNAL_PORT=3000
|
||||||
|
|
||||||
# ===================================
|
# ===================================
|
||||||
# QDRANT (Required for RAG)
|
# QDRANT (Required for RAG)
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ class Settings(BaseSettings):
|
|||||||
"""Derive CORS origins from BASE_URL if not explicitly set"""
|
"""Derive CORS origins from BASE_URL if not explicitly set"""
|
||||||
if v is None:
|
if v is None:
|
||||||
base_url = info.data.get('BASE_URL', 'localhost')
|
base_url = info.data.get('BASE_URL', 'localhost')
|
||||||
return [f"http://{base_url}"]
|
# Support both HTTP and HTTPS for production environments
|
||||||
|
return [f"http://{base_url}", f"https://{base_url}"]
|
||||||
return v if isinstance(v, list) else [v]
|
return v if isinstance(v, list) else [v]
|
||||||
|
|
||||||
# CORS origins (derived from BASE_URL)
|
# CORS origins (derived from BASE_URL)
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./backend
|
||||||
dockerfile: Dockerfile.prod
|
dockerfile: Dockerfile.prod
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@enclava-postgres:5432/${POSTGRES_DB}
|
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@enclava-postgres:5432/${POSTGRES_DB}
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -40,6 +42,8 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./backend
|
||||||
dockerfile: Dockerfile.prod
|
dockerfile: Dockerfile.prod
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
environment:
|
environment:
|
||||||
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@enclava-postgres:5432/${POSTGRES_DB}
|
- DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@enclava-postgres:5432/${POSTGRES_DB}
|
||||||
- REDIS_URL=redis://enclava-redis:6379
|
- REDIS_URL=redis://enclava-redis:6379
|
||||||
@@ -76,11 +80,11 @@ services:
|
|||||||
context: ./frontend
|
context: ./frontend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
target: runner # Use the production stage from multi-stage build
|
target: runner # Use the production stage from multi-stage build
|
||||||
|
env_file:
|
||||||
|
- ./.env
|
||||||
environment:
|
environment:
|
||||||
- BASE_URL=${BASE_URL}
|
- BASE_URL=${BASE_URL}
|
||||||
- NEXT_PUBLIC_BASE_URL=${BASE_URL}
|
- NEXT_PUBLIC_BASE_URL=${BASE_URL}
|
||||||
- BACKEND_INTERNAL_PORT=8000
|
|
||||||
- FRONTEND_INTERNAL_PORT=3000
|
|
||||||
- INTERNAL_API_URL=http://enclava-backend:8000
|
- INTERNAL_API_URL=http://enclava-backend:8000
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- NEXT_TELEMETRY_DISABLED=1
|
- NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|||||||
@@ -68,11 +68,8 @@ services:
|
|||||||
# Required base URL (derives APP/API/WS URLs)
|
# Required base URL (derives APP/API/WS URLs)
|
||||||
- BASE_URL=${BASE_URL}
|
- BASE_URL=${BASE_URL}
|
||||||
- NEXT_PUBLIC_BASE_URL=${BASE_URL}
|
- NEXT_PUBLIC_BASE_URL=${BASE_URL}
|
||||||
# Docker internal ports
|
|
||||||
- BACKEND_INTERNAL_PORT=${BACKEND_INTERNAL_PORT}
|
|
||||||
- FRONTEND_INTERNAL_PORT=${FRONTEND_INTERNAL_PORT}
|
|
||||||
# Internal API URL
|
# Internal API URL
|
||||||
- INTERNAL_API_URL=http://enclava-backend:${BACKEND_INTERNAL_PORT}
|
- INTERNAL_API_URL=http://enclava-backend:8000
|
||||||
depends_on:
|
depends_on:
|
||||||
- enclava-backend
|
- enclava-backend
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -16,8 +16,21 @@ export const viewport: Viewport = {
|
|||||||
initialScale: 1,
|
initialScale: 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to determine the base URL with proper protocol
|
||||||
|
const getBaseUrl = () => {
|
||||||
|
// In production, we need to detect if we're behind HTTPS
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const protocol = window.location.protocol === 'https:' ? 'https' : 'http'
|
||||||
|
const host = process.env.NEXT_PUBLIC_BASE_URL || window.location.hostname
|
||||||
|
return `${protocol}://${host}`
|
||||||
|
}
|
||||||
|
// For build time/server side, default to HTTP for dev, HTTPS for production
|
||||||
|
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http'
|
||||||
|
return `${protocol}://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`
|
||||||
|
}
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
metadataBase: new URL(`http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`),
|
metadataBase: new URL(getBaseUrl()),
|
||||||
title: 'Enclava Platform',
|
title: 'Enclava Platform',
|
||||||
description: 'Secure AI processing platform with plugin-based architecture and confidential computing',
|
description: 'Secure AI processing platform with plugin-based architecture and confidential computing',
|
||||||
keywords: ['AI', 'Enclava', 'Confidential Computing', 'LLM', 'TEE'],
|
keywords: ['AI', 'Enclava', 'Confidential Computing', 'LLM', 'TEE'],
|
||||||
@@ -26,7 +39,7 @@ export const metadata: Metadata = {
|
|||||||
openGraph: {
|
openGraph: {
|
||||||
type: 'website',
|
type: 'website',
|
||||||
locale: 'en_US',
|
locale: 'en_US',
|
||||||
url: `http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`,
|
url: getBaseUrl(),
|
||||||
title: 'Enclava Platform',
|
title: 'Enclava Platform',
|
||||||
description: 'Secure AI processing platform with plugin-based architecture and confidential computing',
|
description: 'Secure AI processing platform with plugin-based architecture and confidential computing',
|
||||||
siteName: 'Enclava',
|
siteName: 'Enclava',
|
||||||
|
|||||||
@@ -91,8 +91,9 @@ export function DocumentUpload({ collections, selectedCollection, onDocumentUplo
|
|||||||
updateProgress(60)
|
updateProgress(60)
|
||||||
|
|
||||||
await uploadFile(
|
await uploadFile(
|
||||||
'/api-internal/v1/rag/documents',
|
|
||||||
uploadingFile.file,
|
uploadingFile.file,
|
||||||
|
'/api-internal/v1/rag/documents',
|
||||||
|
(progress) => updateProgress(progress),
|
||||||
{ collection_id: targetCollection }
|
{ collection_id: targetCollection }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ import {
|
|||||||
import { User, Settings, Lock, LogOut, ChevronDown } from "lucide-react"
|
import { User, Settings, Lock, LogOut, ChevronDown } from "lucide-react"
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
|
|
||||||
|
// Helper function to get API URL with proper protocol
|
||||||
|
const getApiUrl = () => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const protocol = window.location.protocol.slice(0, -1) // Remove ':' from 'https:'
|
||||||
|
const host = window.location.hostname
|
||||||
|
return `${protocol}://${host}`
|
||||||
|
}
|
||||||
|
return `http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`
|
||||||
|
}
|
||||||
|
|
||||||
export function UserMenu() {
|
export function UserMenu() {
|
||||||
const { user, logout } = useAuth()
|
const { user, logout } = useAuth()
|
||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
@@ -62,7 +72,7 @@ export function UserMenu() {
|
|||||||
throw new Error('Authentication required')
|
throw new Error('Authentication required')
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch('/api-internal/v1/auth/change-password', {
|
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/change-password`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@@ -4,6 +4,16 @@ import { createContext, useContext, useState, useEffect, ReactNode } from "react
|
|||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { tokenManager } from "@/lib/token-manager"
|
import { tokenManager } from "@/lib/token-manager"
|
||||||
|
|
||||||
|
// Helper function to get API URL with proper protocol
|
||||||
|
const getApiUrl = () => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
const protocol = window.location.protocol.slice(0, -1) // Remove ':' from 'https:'
|
||||||
|
const host = window.location.hostname
|
||||||
|
return `${protocol}://${host}`
|
||||||
|
}
|
||||||
|
return `http://${process.env.NEXT_PUBLIC_BASE_URL || 'localhost'}`
|
||||||
|
}
|
||||||
|
|
||||||
interface User {
|
interface User {
|
||||||
id: string
|
id: string
|
||||||
email: string
|
email: string
|
||||||
@@ -84,7 +94,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|||||||
const token = await tokenManager.getAccessToken()
|
const token = await tokenManager.getAccessToken()
|
||||||
if (!token) return
|
if (!token) return
|
||||||
|
|
||||||
const response = await fetch('/api-internal/v1/auth/me', {
|
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/me`, {
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': `Bearer ${token}`,
|
'Authorization': `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
@@ -114,7 +124,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
|
|||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api-internal/v1/auth/login', {
|
const response = await fetch(`${getApiUrl()}/api-internal/v1/auth/login`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
|
|
||||||
const API_BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || '';
|
// Dynamic base URL with protocol detection
|
||||||
|
const getApiBaseUrl = (): string => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
// Client-side: use the same protocol as the current page
|
||||||
|
const protocol = window.location.protocol.slice(0, -1); // Remove ':' from 'https:'
|
||||||
|
const host = window.location.hostname;
|
||||||
|
return `${protocol}://${host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server-side: use environment variable or default to localhost
|
||||||
|
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'localhost';
|
||||||
|
const protocol = process.env.NODE_ENV === 'production' ? 'https' : 'http';
|
||||||
|
return `${protocol}://${baseUrl}`;
|
||||||
|
};
|
||||||
|
|
||||||
const axiosInstance = axios.create({
|
const axiosInstance = axios.create({
|
||||||
baseURL: API_BASE_URL,
|
baseURL: getApiBaseUrl(),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
@@ -36,7 +49,7 @@ axiosInstance.interceptors.response.use(
|
|||||||
try {
|
try {
|
||||||
const refreshToken = Cookies.get('refresh_token');
|
const refreshToken = Cookies.get('refresh_token');
|
||||||
if (refreshToken) {
|
if (refreshToken) {
|
||||||
const response = await axios.post(`${API_BASE_URL}/api/auth/refresh`, {
|
const response = await axios.post(`${getApiBaseUrl()}/api/auth/refresh`, {
|
||||||
refresh_token: refreshToken,
|
refresh_token: refreshToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -76,12 +76,20 @@ export const downloadFileFromData = (
|
|||||||
export const uploadFile = async (
|
export const uploadFile = async (
|
||||||
file: File,
|
file: File,
|
||||||
url: string,
|
url: string,
|
||||||
onProgress?: (progress: number) => void
|
onProgress?: (progress: number) => void,
|
||||||
|
additionalData?: Record<string, any>
|
||||||
): Promise<any> => {
|
): Promise<any> => {
|
||||||
try {
|
try {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file);
|
formData.append('file', file);
|
||||||
|
|
||||||
|
// Add additional form data if provided
|
||||||
|
if (additionalData) {
|
||||||
|
Object.entries(additionalData).forEach(([key, value]) => {
|
||||||
|
formData.append(key, value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user