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
16 changes: 16 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.git
.github
.venv
venv
**/__pycache__
*.pyc
*.log
.env
.env.*
!.env.example
model-Thevindu
integrated-backend/data
integrated-backend/build
integrated-backend/tests
integrated-frontend/node_modules
integrated-frontend/dist
23 changes: 23 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Public hostname or IP used by the browser and Keycloak.
PUBLIC_HOST=your-domain.example.com
PUBLIC_ORIGIN=https://your-domain.example.com

# Required secrets. Generate with: openssl rand -hex 32
JWT_SECRET_KEY=replace-with-a-long-random-secret
KEYCLOAK_ADMIN_PASSWORD=replace-with-a-strong-admin-password

# Optional model settings. The backend downloads missing GGUF files into the persistent
# learnmate_models volume from these public Hugging Face files.
LEARNMATE_GENERATOR_REPO=Qwen/Qwen2.5-3B-Instruct-GGUF
LEARNMATE_GENERATOR_FILE=qwen2.5-3b-instruct-q4_k_m.gguf
LEARNMATE_JUDGE_REPO=bartowski/Llama-3.2-3B-Instruct-GGUF
LEARNMATE_JUDGE_FILE=Llama-3.2-3B-Instruct-Q4_K_M.gguf

# Leave these same-origin production defaults unless the architecture changes.
LEARNMATE_GENERATOR_BACKEND=llamacpp
LEARNMATE_JUDGE_BACKEND=llamacpp
LEARNMATE_VECTOR_BACKEND=qdrant
LEARNMATE_MAX_PDF_MB=10
LEARNMATE_MAX_PAGE_COUNT=300
API_WARM_UP=1
API_WARM_MODELS=0
53 changes: 39 additions & 14 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Deploy Application
on:
push:
branches:
- dinura-deployment
- deployment
workflow_dispatch:

jobs:
Expand All @@ -27,11 +27,20 @@ jobs:
run: |
python -m compileall integrated-backend

- name: Frontend build
- name: Frontend lint
run: |
npm ci --prefix integrated-frontend
npm run lint --prefix integrated-frontend

- name: Frontend build
run: |
npm run build --prefix integrated-frontend

- name: Compose configuration check
run: |
cp .env.example .env
docker compose config >/dev/null

deploy:
needs: ci
runs-on: ubuntu-latest
Expand All @@ -51,13 +60,23 @@ jobs:
set -e
cd ~/app
git fetch origin
git checkout dinura-deployment
git reset --hard origin/dinura-deployment
git checkout deployment
git reset --hard origin/deployment

if [ ! -f .env ]; then
cp .env.example .env
echo "~/app/.env is missing. Create it once from .env.example with production secrets."
exit 1
fi

grep -q '^PUBLIC_ORIGIN=https\?://' .env || {
echo "PUBLIC_ORIGIN is missing from ~/app/.env"
exit 1
}

set -a
. ./.env
set +a

chmod 600 .env
if docker info >/dev/null 2>&1; then
DOCKER_CMD="docker"
Expand All @@ -68,15 +87,21 @@ jobs:
exit 1
fi

$DOCKER_CMD compose build
$DOCKER_CMD compose up -d
chmod +x ./scripts/configure-keycloak.sh
$DOCKER_CMD compose up -d --build --remove-orphans
PUBLIC_ORIGIN="$PUBLIC_ORIGIN" KEYCLOAK_ADMIN_PASSWORD="$KEYCLOAK_ADMIN_PASSWORD" \
COMPOSE_CMD="$DOCKER_CMD compose" ./scripts/configure-keycloak.sh
$DOCKER_CMD compose ps

if curl -fsS http://127.0.0.1/api/health >/dev/null 2>&1; then
echo "Backend health check passed"
else
echo "Backend health check failed"
$DOCKER_CMD compose logs --tail 200 backend
exit 1
fi
for attempt in $(seq 1 30); do
if curl -fsS http://127.0.0.1/api/health >/dev/null 2>&1; then
echo "Backend health check passed"
exit 0
fi
sleep 10
done

echo "Backend health check failed"
$DOCKER_CMD compose logs --tail 200 backend
exit 1
EOF
70 changes: 70 additions & 0 deletions AWS_DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# AWS deployment

The repository root is the deployment entrypoint. It runs the frontend, Nginx, FastAPI backend, Keycloak, MongoDB and Qdrant with one Compose project.

## One-time EC2 setup

Use an Ubuntu EC2 instance with enough disk and memory for two local GGUF models. A small instance will start the web stack but may not have enough memory for chat and resource generation.

Install Docker and Git, then clone this repository as the deployment user:

```bash
git clone <repository-url> ~/app
cd ~/app
cp .env.example .env
chmod 600 .env
```

Edit `.env`:

```dotenv
PUBLIC_HOST=your-domain.example.com
PUBLIC_ORIGIN=https://your-domain.example.com
JWT_SECRET_KEY=<random-32-byte-secret>
KEYCLOAK_ADMIN_PASSWORD=<strong-password>
```

A fixed Elastic IP is recommended for a direct EC2 deployment. Point DNS at that address. Allow inbound TCP `80` and `443` in the security group; keep MongoDB, Qdrant, Keycloak and port `8000` private.

For a first HTTP-only smoke test, use `PUBLIC_ORIGIN=http://<elastic-ip>`. Put HTTPS in front of the stack before real users access it, preferably with an AWS Application Load Balancer and ACM certificate, or terminate TLS in Nginx and update `PUBLIC_ORIGIN` to `https://...`.

## Start and update

```bash
cd ~/app
docker compose up -d --build
docker compose ps
PUBLIC_ORIGIN="$(grep '^PUBLIC_ORIGIN=' .env | cut -d= -f2-)" \
KEYCLOAK_ADMIN_PASSWORD="$(grep '^KEYCLOAK_ADMIN_PASSWORD=' .env | cut -d= -f2-)" \
./scripts/configure-keycloak.sh
curl -fsS http://127.0.0.1/api/health
```

The first model request may download the configured GGUF files. They are stored in the `model_data` volume and survive container rebuilds. MongoDB, Qdrant and Keycloak data also use named volumes and survive normal updates.

For later releases:

```bash
git fetch origin
git checkout deployment
git reset --hard origin/deployment
docker compose up -d --build --remove-orphans
PUBLIC_ORIGIN="$(grep '^PUBLIC_ORIGIN=' .env | cut -d= -f2-)" \
KEYCLOAK_ADMIN_PASSWORD="$(grep '^KEYCLOAK_ADMIN_PASSWORD=' .env | cut -d= -f2-)" \
./scripts/configure-keycloak.sh
curl -fsS http://127.0.0.1/api/health
```

Do not run `docker compose down -v` during an application update. The `-v` flag deletes the database, vector, Keycloak and model volumes.

## GitHub Actions CI/CD

Configure these repository secrets:

- `EC2_HOST`: Elastic IP or DNS name
- `EC2_USERNAME`: SSH user, usually `ubuntu`
- `EC2_SSH_KEY`: private key for that user

The workflow in `.github/workflows/deploy.yml` runs on pushes to `deployment` and can also be started manually. The EC2 user must be able to run Docker, and `~/app/.env` must already contain the production secrets. CI never writes secrets into Git.

The workflow builds and tests the frontend, validates the Compose file, updates the checkout, rebuilds changed images, configures the Keycloak client for `PUBLIC_ORIGIN`, and waits for `/api/health`.
Loading
Loading