This guide migrates the backend away from Railway while keeping the Vercel frontend.
- Frontend: Vercel
- Backend: Render Web Service, Docker build from
backend/Dockerfile - MySQL: Aiven MySQL Free
- Redis/Valkey: Aiven Valkey Free or Upstash Redis
- Vector store: Qdrant Cloud Free
Create a MySQL service on Aiven, then copy:
- Host
- Port
- Database name
- User
- Password
Render needs these environment variables:
SPRING_DATASOURCE_URL=jdbc:mysql://<AIVEN_MYSQL_HOST>:<PORT>/<DATABASE>?sslMode=REQUIRED&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
SPRING_DATASOURCE_USERNAME=<AIVEN_MYSQL_USER>
SPRING_DATASOURCE_PASSWORD=<AIVEN_MYSQL_PASSWORD>
For a fresh database, initialize schema with:
db/ai_learning_assistant.sql
db/migrations/2026-04-30_create_ai_config_table.sql
If data is migrated from an old Railway database, import the dump first, then run only missing migration files. At minimum, make sure ai_config exists.
For Aiven Valkey or Upstash Redis, copy host, port, and password.
Render variables:
SPRING_REDIS_HOST=<REDIS_HOST>
SPRING_REDIS_PORT=<REDIS_TLS_PORT>
SPRING_REDIS_PASSWORD=<REDIS_PASSWORD>
SPRING_REDIS_DATABASE=0
SPRING_REDIS_SSL_ENABLED=true
If the provider gives a non-TLS port, set SPRING_REDIS_SSL_ENABLED=false.
Create a free Qdrant cluster, then copy:
- Cluster URL
- API Key
Render variables:
APP_QDRANT_ENABLED=true
APP_QDRANT_BASE_URL=https://<QDRANT_CLUSTER_HOST>
APP_QDRANT_API_KEY=<QDRANT_API_KEY>
APP_QDRANT_COLLECTION_NAME=material_segment_vectors
The backend creates the collection lazily when embedding/retrieval runs.
Recommended manual setup:
Service Type: Web Service
Repository: Nyx-Amanises/AI-Intelligent-Learning-Assistant-System
Runtime: Docker
Root Directory: backend
Dockerfile Path: Dockerfile
Plan: Free
Or use the repository render.yaml Blueprint.
Required Render variables:
APP_CORS_ALLOWED_ORIGINS=https://ai-intelligent-learning-assistant-s.vercel.app
APP_FILE_UPLOAD_DIR=/tmp/ai-learning-uploads
APP_AI_CONFIG_FILE=/tmp/ai-config.json
APP_AI_ENABLED=true
APP_AI_MOCK_MODE=true
APP_JWT_SECRET=<random-long-secret>
SPRING_DATASOURCE_URL=<see section 1>
SPRING_DATASOURCE_USERNAME=<see section 1>
SPRING_DATASOURCE_PASSWORD=<see section 1>
SPRING_REDIS_HOST=<see section 2>
SPRING_REDIS_PORT=<see section 2>
SPRING_REDIS_PASSWORD=<see section 2>
SPRING_REDIS_SSL_ENABLED=true
APP_QDRANT_ENABLED=true
APP_QDRANT_BASE_URL=<see section 3>
APP_QDRANT_API_KEY=<see section 3>
APP_QDRANT_COLLECTION_NAME=material_segment_vectors
AI keys do not need to be set in Render if the admin user configures the shared key in the app.
After Render deploys successfully, copy the Render backend URL, then set this in Vercel:
VITE_API_BASE_URL=https://<RENDER_BACKEND_DOMAIN>/api
Redeploy Vercel after changing the variable.
- Open the backend health smoke check:
https://<RENDER_BACKEND_DOMAIN>/api/ai/config
Unauthenticated requests should return an auth error, which still proves the backend is reachable.
- Open the frontend, log in as
admin. - Go to AI config, switch to shared config, save the shared API key.
- Upload a small document and confirm parse -> embedding -> RAG retrieval.
Render free web services sleep after inactivity. First request after sleep can be slow.
Render free web service storage is not persistent. This project should treat uploads as temporary input files and rely on parsed database records plus Qdrant vectors for long-lived data.