Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c9c70e4
Redesign the app shell and key pages with an editorial masthead nav
Tharumini03 Aug 20, 2026
d2f1139
Fix Keycloak logout and drop the dead local-auth path
Tharumini03 Aug 20, 2026
54b9ed2
Feedbacks done
Dinurang Sep 6, 2026
957db0b
Prepare AWS deployment and CI/CD
Dinurang Sep 6, 2026
9ca7330
chore: Update configurations for HTTPS and production domain
Dinurang Sep 8, 2026
5b5e4c7
ci: Switch GitHub Actions to use AWS SSM for deployment
Dinurang Sep 8, 2026
a7782a2
fix: Base64 encode SSM deployment script to fix AWS CLI parsing errors
Dinurang Sep 8, 2026
52b07a9
ci: Fix SSM command logging to show errors when execution fails
Dinurang Sep 8, 2026
9892c3b
ci: Harden SSM deployment workflow and add EC2 deploy script
Dinurang Sep 8, 2026
bdf607f
fix: Run SSM deploy as ubuntu and harden bootstrap script
Dinurang Sep 8, 2026
b7f6fc9
fix: strip Windows carriage returns from decoded env file
Dinurang Sep 8, 2026
e898ae9
yml update1
Dinurang Sep 8, 2026
7e33040
yml update2
Dinurang Sep 8, 2026
0ca0966
yml update3
Dinurang Sep 8, 2026
167f722
docs: rewrite AWS deployment guide with concrete setup steps
Dinurang Sep 8, 2026
ec220ee
fix: wait for Keycloak readiness before configuring client
Dinurang Sep 8, 2026
f4fe586
up4
Dinurang Sep 8, 2026
5d16016
fix: limit Mongo cache, add swap, harden healthchecks
Dinurang Sep 8, 2026
4e315d3
ci: update Node.js to 22 LTS
Dinurang Sep 8, 2026
7933724
fix: use exec-form Mongo healthcheck, add Mongo logs on failure
Dinurang Sep 8, 2026
5bec70c
fix: check Keycloak health from inside container, not host
Dinurang Sep 8, 2026
2dd02a2
fix: wait for each service independently instead of compose cascade
Dinurang Sep 8, 2026
85cd6c9
fix: simplify Keycloak healthcheck, add per-service wait with diagnos…
Dinurang Sep 8, 2026
c74a4af
fix: downgrade Mongo 8->7 for kernel 6.19+ compatibility, force-recre…
Dinurang Sep 9, 2026
fbba9f1
fix: wait for Docker health status during EC2 deployment
Dinurang Sep 9, 2026
d301c94
fix: keep MongoDB 8 compatible with persistent data
Dinurang Sep 9, 2026
cc8ffdb
fix: use fresh Mongo 7 volume on Ubuntu 24.04 kernel
Dinurang Sep 9, 2026
3a0bec8
fix: probe Keycloak 26 management health endpoint
Dinurang Sep 9, 2026
2599861
fix: remove Keycloak healthcheck and healthy dependency to break dead…
Dinurang Sep 9, 2026
b844233
fix: remove invalid depends_on condition for Keycloak
Dinurang Sep 9, 2026
ed16f35
fix: simplify Keycloak readiness check to TCP port probe
Dinurang Sep 9, 2026
747c7fb
fix: check backend health via docker compose exec, not host curl
Dinurang Sep 9, 2026
0ddf55a
fix: add SPA routing to frontend Nginx, update Dockerfile
Dinurang Sep 9, 2026
4750598
ci: trigger redeployment with updated environment config
Dinurang Sep 9, 2026
9dccafc
Merge remote-tracking branch 'origin/deployment' into tharumini-dev
Tharumini03 Sep 13, 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
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=learnmateai.dinurag.dev
PUBLIC_ORIGIN=https://learnmateai.dinurag.dev

# 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
147 changes: 102 additions & 45 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ name: Deploy Application
on:
push:
branches:
- dinura-deployment
- deployment
workflow_dispatch:

concurrency:
group: deploy-production
cancel-in-progress: false

jobs:
ci:
runs-on: ubuntu-latest
Expand All @@ -21,62 +25,115 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: '22'

- name: Backend syntax check
run: python -m compileall integrated-backend/app integrated-backend/learnmate

- name: Frontend lint
run: |
python -m compileall integrated-backend
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: |
npm ci --prefix integrated-frontend
npm run build --prefix integrated-frontend
cp .env.example .env
docker compose config >/dev/null

deploy:
needs: ci
runs-on: ubuntu-latest
steps:
- name: Deploy to EC2 via SSH
uses: webfactory/ssh-agent@v0.9.0
- name: Checkout repository
uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
ssh-private-key: ${{ secrets.EC2_SSH_KEY }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}

- name: SSH and deploy latest app
- name: Deploy via AWS SSM
env:
EC2_HOST: ${{ secrets.EC2_HOST }}
EC2_USERNAME: ${{ secrets.EC2_USERNAME }}
EC2_INSTANCE_ID: ${{ secrets.EC2_INSTANCE_ID }}
EC2_APP_DIR: ${{ secrets.EC2_APP_DIR }}
APP_ENV_FILE_B64: ${{ secrets.APP_ENV_FILE_B64 }}
GIT_DEPLOY_TOKEN: ${{ secrets.GIT_DEPLOY_TOKEN }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
set -e
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${EC2_USERNAME}@${EC2_HOST} <<'EOF'
set -e
cd ~/app
git fetch origin
git checkout dinura-deployment
git reset --hard origin/dinura-deployment

if [ ! -f .env ]; then
cp .env.example .env
fi

chmod 600 .env
if docker info >/dev/null 2>&1; then
DOCKER_CMD="docker"
elif sudo -n docker info >/dev/null 2>&1; then
DOCKER_CMD="sudo -n docker"
else
echo "Docker daemon is not accessible for deployment user"
exit 1
fi

$DOCKER_CMD compose build
$DOCKER_CMD compose up -d
$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
EOF
set -euo pipefail

if [ -z "${EC2_INSTANCE_ID:-}" ] || [ -z "${EC2_APP_DIR:-}" ]; then
echo "Missing required secrets: EC2_INSTANCE_ID and EC2_APP_DIR must be set." >&2
exit 1
fi

echo "Checking that instance ${EC2_INSTANCE_ID} is registered with SSM..."
ONLINE=$(aws ssm describe-instance-information \
--filters "Key=InstanceIds,Values=${EC2_INSTANCE_ID}" \
--query "length(InstanceInformationList)" \
--output text)
if [ "${ONLINE}" != "1" ]; then
echo "Instance ${EC2_INSTANCE_ID} is not online in SSM." >&2
exit 1
fi

PARAMS_FILE=$(mktemp)
python3 scripts/build-ssm-deploy-params.py > "${PARAMS_FILE}"

echo "Sending SSM command to instance ${EC2_INSTANCE_ID}"
COMMAND_ID=$(aws ssm send-command \
--instance-ids "${EC2_INSTANCE_ID}" \
--document-name "AWS-RunShellScript" \
--comment "Deploy LearnMate via GitHub Actions (${GITHUB_REPOSITORY}@${GITHUB_SHA})" \
--timeout-seconds 3600 \
--parameters "file://${PARAMS_FILE}" \
--query "Command.CommandId" \
--output text)
rm -f "${PARAMS_FILE}"

echo "Waiting for SSM command ${COMMAND_ID} to complete..."

STATUS="InProgress"
while [ "$STATUS" = "InProgress" ] || [ "$STATUS" = "Pending" ] || [ "$STATUS" = "Delayed" ]; do
sleep 15
STATUS=$(aws ssm get-command-invocation \
--instance-id "${EC2_INSTANCE_ID}" \
--command-id "${COMMAND_ID}" \
--query "Status" \
--output text)
echo "Current status: $STATUS"
done

if [ "$STATUS" != "Success" ]; then
echo "SSM command did not finish successfully. Fetching logs..."
fi

echo "=== STANDARD ERROR ==="
aws ssm get-command-invocation \
--instance-id "${EC2_INSTANCE_ID}" \
--command-id "${COMMAND_ID}" \
--query "StandardErrorContent" \
--output text

echo "=== STANDARD OUTPUT ==="
aws ssm get-command-invocation \
--instance-id "${EC2_INSTANCE_ID}" \
--command-id "${COMMAND_ID}" \
--query "StandardOutputContent" \
--output text

STATUS=$(aws ssm get-command-invocation \
--instance-id "${EC2_INSTANCE_ID}" \
--command-id "${COMMAND_ID}" \
--query "Status" \
--output text)

if [ "$STATUS" != "Success" ]; then
echo "Deployment failed with status: ${STATUS}" >&2
exit 1
fi
3 changes: 3 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"recommendations": []
}
Loading
Loading