Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Brave Search API Key
# Get from https://brave.com/search/api/
BRAVE_API_KEY=your_brave_api_key_here

# OpenAI API Key
# Get from https://platform.openai.com/api-keys
OPENAI_API_KEY=sk-your_openai_api_key_here

# Optional: Cache TTL in seconds (default: 300)
CACHE_TTL_SECONDS=300

# Optional: Port (default: 3000)
PORT=3000
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
test:
name: Test
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Run tests
run: bun test

- name: Type check
run: bun run tsc --noEmit
93 changes: 93 additions & 0 deletions DEPLOY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# QueryX Deployment Guide

## Prerequisites

- [Railway](https://railway.app) account
- [Railway CLI](https://docs.railway.app/guides/cli) installed
- Brave Search API key
- OpenAI API key

## Step 1: Install Railway CLI

```bash
# Install via npm
npm install -g @railway/cli

# Or via brew
brew install railway
```

## Step 2: Login to Railway

```bash
railway login
```

## Step 3: Initialize Project

```bash
# Navigate to your project directory
cd queryx

# Initialize Railway project
railway init

# Follow the prompts to create a new project
```

## Step 4: Configure Environment Variables

Set the required environment variables via the Railway dashboard:

1. Go to your project on [Railway Dashboard](https://railway.dashboard)
2. Click on the environment (e.g., "production")
3. Click "Variables" tab
4. Add the following variables:

| Variable | Description | Required |
|----------|-------------|----------|
| `BRAVE_API_KEY` | Brave Search API key | Yes |
| `OPENAI_API_KEY` | OpenAI API key for synthesis | Yes |
| `CACHE_TTL_SECONDS` | Cache TTL in seconds (default: 300) | No |
| `PORT` | Server port (default: 3000) | No |

## Step 5: Deploy

```bash
railway up
```

The deployment will:
1. Build the Docker container
2. Start the server on port 3000
3. Run health checks on `/health`

## Step 6: Verify Deployment

```bash
# Check health endpoint
curl https://your-project-name.up.railway.app/health

# Should return: { "status": "ok" }
```

## Step 7: Custom Domain Setup (Optional)

1. Go to your project settings on Railway
2. Click "Domains"
3. Click "Generate Domain" for Railway-provided domain
4. Or add custom domain (e.g., `queryx.run`)

## Troubleshooting

### Health check fails
- Ensure `PORT` is set to `3000`
- Check logs: `railway logs`

### API errors
- Verify `BRAVE_API_KEY` is valid
- Verify `OPENAI_API_KEY` has credits

### Rate limiting
- Reduce `CACHE_TTL_SECONDS` for shorter cache
- Check Brave API rate limits
9 changes: 9 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM oven/bun:1 AS base
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
COPY . .
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["bun", "run", "src/index.ts"]
13 changes: 13 additions & 0 deletions railway.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "https://railway.app/railway.schema.json",
"build": {
"builder": "DOCKERFILE"
},
"deploy": {
"healthcheckPath": "/health",
"healthcheckTimeout": 10,
"restartPolicyType": "ON_FAILURE",
"restartPolicyMaxRetries": 3,
"numReplicas": 1
}
}
61 changes: 61 additions & 0 deletions scripts/smoke-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash
# Smoke test script for QueryX deployment

set -e

# Get base URL from first argument or use default
BASE_URL="${1:-http://localhost:3000}"

echo "Running smoke tests against $BASE_URL"
echo "======================================"

# Test 1: Health check
echo "Test 1: Health check..."
HEALTH_RESPONSE=$(curl -s -w "\n%{http_code}" "$BASE_URL/health")
HTTP_CODE=$(echo "$HEALTH_RESPONSE" | tail -n1)
BODY=$(echo "$HEALTH_RESPONSE" | head -n-1)

if [ "$HTTP_CODE" != "200" ]; then
echo "FAIL: Health check returned HTTP $HTTP_CODE"
echo "Response: $BODY"
exit 1
fi

if ! echo "$BODY" | grep -q "ok"; then
echo "FAIL: Health response does not contain 'ok'"
echo "Response: $BODY"
exit 1
fi

echo "PASS: Health check returned 200 with { status: 'ok' }"

# Test 2: /v1/search returns 402 without payment
echo ""
echo "Test 2: /v1/search without payment..."
SEARCH_RESPONSE=$(curl -s -w "\n%{http_code}" "$BASE_URL/v1/search?q=test")
HTTP_CODE=$(echo "$SEARCH_RESPONSE" | tail -n1)

if [ "$HTTP_CODE" != "402" ]; then
echo "FAIL: /v1/search should return 402 without payment, got $HTTP_CODE"
exit 1
fi

echo "PASS: /v1/search returns 402 Payment Required without payment"

# Test 3: Verify x402 headers in 402 response
echo ""
echo "Test 3: Check x402 headers in 402 response..."
HEADERS=$(curl -s -D - "$BASE_URL/v1/search?q=test" -o /dev/null)

if ! echo "$HEADERS" | grep -qi "x402"; then
echo "FAIL: 402 response missing x402 headers"
echo "Headers: $HEADERS"
exit 1
fi

echo "PASS: 402 response includes x402 headers"

echo ""
echo "======================================"
echo "All smoke tests passed!"
exit 0