Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2b4efd7
deployment ready
hellonish Apr 3, 2026
e9eddbb
updated dep
hellonish Apr 3, 2026
579abc3
Docker Files Update - Pull instead of Build
hellonish Apr 3, 2026
be22831
fix healthchecks
hellonish Apr 3, 2026
f272843
fix healthchecks, remove local qdrant, optimize for t3.micro
hellonish Apr 3, 2026
ad4a361
caddy prod update
hellonish Apr 3, 2026
24126d6
INTERNAL API FIX
hellonish Apr 3, 2026
179668c
add Google OAuth env vars to frontend service
hellonish Apr 3, 2026
7fd923b
add NEXT_PUBLIC_API_URL build arg to frontend Dockerfile
hellonish Apr 3, 2026
ef800e5
MIgrations fix
hellonish Apr 3, 2026
f3f6f14
recover orphaned running jobs on worker startup
hellonish Apr 3, 2026
4d20c27
fix worker OOM crash after planning phase
hellonish Apr 3, 2026
9d47024
use in-memory Qdrant for worker (no Qdrant server configured)
hellonish Apr 3, 2026
6e107bb
add per-attempt timeout to all tools to prevent indefinite hangs
hellonish Apr 3, 2026
5f1b60b
show warning on frontend when job runs longer than 10 minutes
hellonish Apr 3, 2026
f24f584
use QDRANT_LOCATION env var to connect to Qdrant Cloud
hellonish Apr 3, 2026
f9c1345
handle 429 rate limit error on job creation in dashboard
hellonish Apr 3, 2026
36ea1a1
fix orphan recovery to also catch pending jobs
hellonish Apr 3, 2026
db4c002
fix: run Qdrant cache ops in thread pool with timeout to prevent even…
hellonish Apr 3, 2026
2edb13c
fix: move blocking ML/Qdrant ops to thread pool, add sentence-transfo…
hellonish Apr 3, 2026
ef245c1
swap sentence-transformers for fastembed (~1.4GB lighter)
hellonish Apr 3, 2026
9e8228d
swap sentence-transformers for fastembed, add Qdrant payload index fo…
hellonish Apr 3, 2026
275ca27
fix: remove unused PayloadIndexParams import that broke create_collec…
hellonish Apr 3, 2026
d92a253
merging before cleaning v1
hellonish Apr 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# ── Dockerignore — keep images lean ──────────────────────────────────────────
.git
.github
.venv
node_modules
__pycache__
*.pyc
.pytest_cache
.mypy_cache
.env
.env.*
!.env.production
blob_storage/
*.md
!README.md
.next
frontend/.next
frontend/node_modules
deploy/
*.egg-info
dist/
build/
.DS_Store
*.log
70 changes: 70 additions & 0 deletions .env.production
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# ── Production Environment Template ──────────────────────────────────────────
# Copy to .env on the server and fill in ALL values.
# Generate secrets with: python -c "import secrets; print(secrets.token_urlsafe(64))"

# ── Docker Hub ────────────────────────────────────────────────────────────────
DOCKERHUB_USER= # Your Docker Hub username (e.g. hellonish)

# ── Database (used by docker-compose.prod.yml for POSTGRES_PASSWORD) ────────
POSTGRES_USER=singularity
POSTGRES_PASSWORD= # REQUIRED: generate a strong password

# ── LLM providers — at least one required ───────────────────────────────────
GROK_API_KEY= # xAI Grok (primary model)
GOOGLE_API_KEY= # Google Gemini (optional)
DEEPSEEK_API_KEY= # DeepSeek (optional)

# ── Search & retrieval APIs ─────────────────────────────────────────────────
TAVILY_API_KEY= # Tavily — web search
SERPAPI_API_KEY= # SerpAPI — web search fallback
GITHUB_TOKEN= # GitHub — code search (optional, public repos work)
GOOGLE_BOOKS_API_KEY= # Google Books (optional)
NCBI_EMAIL= # NCBI PubMed — required by their API policy

# ── Vector Store (Qdrant Cloud) ─────────────────────────────────────────────
# Using Qdrant Cloud instead of local container to save memory on t3.micro
QDRANT_LOCATION=https://YOUR_CLUSTER_URL.aws.cloud.qdrant.io # Qdrant Cloud URL
QDRANT_API_KEY= # Qdrant Cloud API key
QDRANT_FORCE_IN_MEMORY=0
QDRANT_CONNECT_TIMEOUT=3

# ── Auth ─────────────────────────────────────────────────────────────────────
JWT_SECRET= # REQUIRED: generate with openssl rand -hex 64
JWT_ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=15
REFRESH_TOKEN_EXPIRE_DAYS=30

# BYOK encryption key for user LLM API keys
# Generate: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
LLM_CREDENTIALS_ENCRYPTION_KEY=

# ── Google OAuth ─────────────────────────────────────────────────────────────
# Create credentials at: https://console.cloud.google.com/apis/credentials
# Add your domain to Authorized JavaScript origins and Authorized redirect URIs:
# https://YOUR_DOMAIN/api/auth/callback/google
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

# ── NextAuth ─────────────────────────────────────────────────────────────────
NEXTAUTH_URL=https://YOUR_DOMAIN # REQUIRED: your domain with https://
NEXTAUTH_SECRET= # REQUIRED: generate with openssl rand -hex 32
NEXT_PUBLIC_API_URL=https://YOUR_DOMAIN # Same domain (Caddy proxies to API)

# ── Blob Storage ─────────────────────────────────────────────────────────────
BLOB_STORE=local
LOCAL_BLOB_DIR=./blob_storage

# ── Observability ────────────────────────────────────────────────────────────
SENTRY_DSN= # Optional: Sentry error tracking
ENVIRONMENT=production

# ── CORS ─────────────────────────────────────────────────────────────────────
FRONTEND_URL=https://YOUR_DOMAIN
CORS_ORIGINS=["https://YOUR_DOMAIN"]

# ── Domain (used by Caddy) ──────────────────────────────────────────────────
DOMAIN=YOUR_DOMAIN # REQUIRED: for Caddy SSL cert provisioning

# ── Quotas ───────────────────────────────────────────────────────────────────
DEFAULT_DAILY_TOKEN_BUDGET=1000000
MAX_CONCURRENT_JOBS_PER_USER=2
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ cmd.txt

/how_to_document_code.md
.gstack/

*.pem
52 changes: 52 additions & 0 deletions Dockerfile.frontend
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Production Dockerfile for Next.js Frontend
# Multi-stage build using standalone output
# Build context: project root (docker-compose.prod.yml sets context: .)

# Stage 1: deps — install dependencies
FROM node:20-alpine AS deps
WORKDIR /app

COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci

# Stage 2: builder — build the app
FROM node:20-alpine AS builder
WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules
COPY frontend/ .

# NEXT_PUBLIC_* vars are baked into the client bundle at build time.
# Pass via --build-arg or docker compose build args.
ARG NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}

ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

# Stage 3: runner — minimal production image
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs

# Copy standalone output (requires output: 'standalone' in next.config.ts)
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1

CMD ["node", "server.js"]
47 changes: 47 additions & 0 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Production Dockerfile for API + Worker
# Multi-stage build optimized for small image size

# Stage 1: builder — install system deps and Python packages
FROM python:3.12-slim AS builder

RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /build

COPY requirements.txt requirements_api.txt ./
RUN pip install --upgrade pip && \
pip install --no-cache-dir -r requirements.txt -r requirements_api.txt

# Stage 2: runtime image
FROM python:3.12-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*

# Non-root user for security
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser

# Copy installed packages from builder
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin

WORKDIR /app

# Copy application code
COPY . .

# Create blob storage directory
RUN mkdir -p /app/blob_storage && chown -R appuser:appuser /app

USER appuser

EXPOSE 8000

HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')"

CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"]
Loading
Loading