diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..3351c85 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +# The repository owner reviews changes before they reach the protected main branch. +* @gopalmani diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 35d6202..f618b5f 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -1,7 +1,8 @@ name: Backend on: - push: { paths: ['apps/api/**', 'evaluations/**', '.github/workflows/backend.yml'] } - pull_request: { paths: ['apps/api/**', 'evaluations/**', '.github/workflows/backend.yml'] } + push: + branches: [main] + pull_request: {} jobs: test: runs-on: ubuntu-latest diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 831958c..d02b735 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -1,7 +1,8 @@ name: Frontend on: - push: { paths: ['apps/web/**', '.github/workflows/frontend.yml'] } - pull_request: { paths: ['apps/web/**', '.github/workflows/frontend.yml'] } + push: + branches: [main] + pull_request: {} jobs: verify: runs-on: ubuntu-latest diff --git a/README.md b/README.md index ce959fe..91610a0 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ The API validates question size, limits generated SQL length, rejects comments/m ## Render deployment -`render.yaml` defines the API, web app, and PostgreSQL database. Secrets and the browser API URL require dashboard entry. Follow [the exact Blueprint procedure](docs/deployment.md); this repository prepares deployment but has not deployed or connected a Render account. +`render.yaml` defines the API and web app. The application database is an external PostgreSQL service such as Supabase, supplied through the backend-only `DATABASE_URL` secret. Both services deploy after CI passes for every commit merged into `main`. Follow [the exact deployment procedure](docs/deployment.md); secrets and the browser API URL still require dashboard entry. ## Limitations and roadmap diff --git a/docs/deployment.md b/docs/deployment.md index a0d58d7..dc65d0a 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -15,11 +15,25 @@ docker compose exec ollama ollama pull sqlcoder Use the first generated value for `CONNECTION_ENCRYPTION_KEY` and the second for `AUTH_SIGNING_KEY`. Open web at `http://localhost:4028`, API docs at `http://localhost:8000/docs`, and check `/health` then `/ready`. Configure a provider for generation. BYOD databases must be publicly reachable PostgreSQL on port 5432 with SSL and a read-only role. +## Supabase application database + +QueryMindAI uses PostgreSQL for its own encrypted connection records, schema snapshots, drafts, verified examples, query history, and audit events. This application database is separate from the customer databases connected through the UI. + +Create a Supabase project, then open **Connect** in its dashboard. For a Render service, use the **Session pooler** connection string on port `5432`: it supports persistent application traffic over IPv4. Supabase direct connections are IPv6 by default and may require its paid IPv4 add-on, while transaction pooling on port `6543` has prepared-statement constraints. See [Supabase connection guidance](https://supabase.com/docs/guides/database/connecting-to-postgres). + +Convert the URL prefix for the installed SQLAlchemy driver and require TLS: + +```text +postgresql+psycopg2://postgres.PROJECT_REF:URL_ENCODED_PASSWORD@SESSION_POOLER_HOST:5432/postgres?sslmode=require +``` + +Enter the complete value only in Render's secret `DATABASE_URL` field. Never commit it, expose it through `NEXT_PUBLIC_*`, or paste it into an issue or pull request. If a password has been shared outside the secret manager, rotate it in **Supabase → Project Settings → Database** before deployment. + ## Render Blueprint procedure 1. Push this repository to GitHub. In Render choose **New → Blueprint**, connect that repository, and select `render.yaml`. -2. Review creation of `querymind-postgres`, `querymind-api`, and `querymind-web`. Select paid plans where the Blueprint/free availability differs for your account or region. -3. Enter backend secrets in the non-synced fields: Groq `LLM_API_KEY`, a Fernet `CONNECTION_ENCRYPTION_KEY`, and an independent random `AUTH_SIGNING_KEY`. Never reuse or commit these values. +2. Review creation or update of `querymind-api` and `querymind-web`. The Blueprint intentionally does not provision a Render PostgreSQL database. +3. Enter backend secrets in the non-synced fields: Supabase session-pooler `DATABASE_URL`, Groq `LLM_API_KEY`, a Fernet `CONNECTION_ENCRYPTION_KEY`, and an independent random `AUTH_SIGNING_KEY`. Never reuse or commit these values. 4. Set `CORS_ALLOW_ORIGINS` on the API to the final HTTPS web origin, without a trailing slash. 5. Deploy the API. On the free tier, the API start command runs `alembic upgrade head` before starting Uvicorn because Render does not support pre-deploy commands for free services. Confirm `https:///health` and `/ready`. 6. Set `NEXT_PUBLIC_API_URL` on `querymind-web` to `https:///api/v1`, then trigger a clean frontend deploy. Render does not provide a supported Blueprint interpolation from another web service’s eventual public hostname into a Next.js build variable; this manual build-time step is required. @@ -28,9 +42,9 @@ Use the first generated value for `CONNECTION_ENCRYPTION_KEY` and the second for The Blueprint keeps local embedding features disabled because the standard API build omits the large SentenceTransformer runtime. To enable them, change the API build command to `pip install -r requirements-embeddings.txt`, provision adequate memory, then set the feature flags true. Groq announced free/developer-tier retirement of `llama-3.3-70b-versatile` for August 16, 2026; replace `LLM_FALLBACK_MODEL` before that date if the deployment is affected. -Build filters deploy the API for backend/shared deployment changes and the web for frontend/shared deployment changes. `render.yaml` contains no real API keys. This repository has been prepared and syntax-checked locally; no Render account or live deployment has been connected by this work. +Both services use repository-root commands and intentionally omit build filters. Every commit merged into the linked `main` branch runs both GitHub Actions workflows; Render waits for checks to pass, then deploys both the API and web service. Confirm the Blueprint is linked to `main` and **Auto Sync** is enabled. `render.yaml` contains no database password or API key. -A merge to `main` does not unconditionally rebuild both services. Render evaluates each service's `buildFilter`: changes under `apps/web/**` deploy the web service, changes under `apps/api/**` deploy the API, changes touching both deploy both, and shared files listed in both filters (such as `render.yaml`) trigger both. This avoids unnecessary backend deploys for UI-only pull requests. +Removing the old `querymind-postgres` resource from the Blueprint does not migrate its data. The suspended database must be deleted separately in Render after confirming Supabase migrations and API readiness. Existing metadata is lost unless it is exported from Render and imported into Supabase first. ## Customer read-only PostgreSQL role diff --git a/render.yaml b/render.yaml index de0e28c..0d6d9af 100644 --- a/render.yaml +++ b/render.yaml @@ -1,26 +1,17 @@ -databases: - - name: querymind-postgres - plan: free - databaseName: querymind - user: querymind - services: - type: web name: querymind-api plan: free runtime: python - rootDir: apps/api - buildCommand: pip install -r requirements.txt - startCommand: alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port $PORT + buildCommand: pip install -r apps/api/requirements.txt + startCommand: cd apps/api && alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port $PORT healthCheckPath: /health - autoDeployTrigger: commit - buildFilter: - paths: [apps/api/**, render.yaml, docker-compose.yml, .env.example] + autoDeployTrigger: checksPass envVars: - key: PYTHON_VERSION value: 3.12.10 - key: DATABASE_URL - fromDatabase: { name: querymind-postgres, property: connectionString } + sync: false - key: APP_ENV value: production - key: ENABLE_EXTERNAL_CONNECTIONS @@ -67,12 +58,9 @@ services: name: querymind-web plan: free runtime: node - rootDir: apps/web - buildCommand: npm ci && npm run build - startCommand: npm run start -- -p $PORT - autoDeployTrigger: commit - buildFilter: - paths: [apps/web/**, render.yaml, .env.example] + buildCommand: cd apps/web && npm ci && npm run build + startCommand: cd apps/web && npm run start -- -p $PORT + autoDeployTrigger: checksPass envVars: - key: NODE_VERSION value: 20.19.5