-
-
Notifications
You must be signed in to change notification settings - Fork 8
Containerize with Docker Compose and Vector DB Option #668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| # Cloud Deployment Guide for QCX | ||
|
|
||
| This guide provides instructions for deploying the QCX stack (Next.js, PostgreSQL with pgvector/PostGIS, and Qdrant) to various cloud platforms. | ||
|
|
||
| ## Infrastructure Overview | ||
|
|
||
| The application consists of: | ||
| 1. **QCX Web App**: Next.js application running on Bun. | ||
| 2. **PostgreSQL**: Database with `pgvector` and `PostGIS` extensions. | ||
| 3. **Qdrant**: High-performance vector database (optional, for advanced vector search). | ||
|
|
||
| --- | ||
|
|
||
| ## 1. Deploying with Docker Compose (VPS / EC2 / Compute Engine) | ||
|
|
||
| The easiest way to deploy the entire stack is using `docker-compose`. | ||
|
|
||
| 1. **Clone the repository** on your server. | ||
| 2. **Create a `.env` file** based on the environment variables in `docker-compose.yaml`. | ||
| 3. **Run the stack**: | ||
| ```bash | ||
| docker-compose up -d --build | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 2. Deploying to Render | ||
|
|
||
| Render is a great choice for managed services. | ||
|
|
||
| ### PostgreSQL (Managed) | ||
| 1. Create a **New PostgreSQL** instance on Render. | ||
| 2. **Note**: Standard Render Postgres does not include `pgvector` or `PostGIS` by default on all plans. You may need to use a Docker-based Postgres on Render or ensure your plan supports these extensions. | ||
| 3. If using Render's managed Postgres, run the extensions command manually via a SQL client: | ||
| ```sql | ||
| CREATE EXTENSION IF NOT EXISTS postgis; | ||
| CREATE EXTENSION IF NOT EXISTS vector; | ||
| ``` | ||
|
|
||
| ### Web Service | ||
| 1. Create a **New Web Service** pointing to your repository. | ||
| 2. Select **Docker** as the runtime. | ||
| 3. Specify the **Dockerfile path** as `Dockerfile`. | ||
| 4. Add environment variables: | ||
| * `DATABASE_URL`: Your Render Postgres connection string. | ||
| * `EXECUTE_MIGRATIONS`: `true` | ||
| * `NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN`: Your Mapbox token. | ||
| * (Add other necessary API keys like Google, xAI, etc.) | ||
|
|
||
| ### Qdrant (Optional) | ||
| 1. Create a **New Private Service** or **Web Service**. | ||
| 2. Select **Docker** as the runtime. | ||
| 3. Use the image: `qdrant/qdrant:latest`. | ||
| 4. Set `QDRANT_URL` in your Web Service to point to this service. | ||
|
|
||
| --- | ||
|
|
||
| ## 3. Deploying to Google Cloud (GCP) | ||
|
|
||
| ### Cloud Run | ||
| 1. **Build and Push** the image to Google Artifact Registry: | ||
| ```bash | ||
| docker build -t gcr.io/YOUR_PROJECT/qcx . | ||
| docker push gcr.io/YOUR_PROJECT/qcx | ||
| ``` | ||
| 2. **Deploy to Cloud Run**: | ||
| ```bash | ||
| gcloud run deploy qcx --image gcr.io/YOUR_PROJECT/qcx --platform managed | ||
| ``` | ||
|
|
||
| ### Cloud SQL | ||
| 1. Create a **Cloud SQL for PostgreSQL** instance (version 15+). | ||
| 2. Cloud SQL supports both `pgvector` and `postgis`. Enable them via: | ||
| ```sql | ||
| CREATE EXTENSION IF NOT EXISTS postgis; | ||
| CREATE EXTENSION IF NOT EXISTS vector; | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 4. Vector Database Options | ||
|
|
||
| QCX is configured to support two vector database options: | ||
|
|
||
| 1. **PostgreSQL (pgvector)**: Integrated into the main database. Best for smaller datasets and simplicity. | ||
| 2. **Qdrant**: Dedicated vector database. Recommended for large-scale production use cases requiring high performance and advanced filtering. | ||
|
|
||
| To use Qdrant, ensure the `QDRANT_URL` environment variable is set in your application environment. | ||
|
|
||
| --- | ||
|
|
||
| ## 5. Security Checklist | ||
|
|
||
| * [ ] Change default passwords in `docker-compose.yaml`. | ||
| * [ ] Use SSL for database connections in production (`ssl=true` in `DATABASE_URL`). | ||
| * [ ] Set `NODE_ENV=production`. | ||
| * [ ] Ensure all sensitive API keys are stored as secrets, not committed to code. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| FROM postgres:16-alpine | ||
|
|
||
| # Install build dependencies and pgvector | ||
| RUN apk add --no-cache --virtual .build-deps \ | ||
| git \ | ||
| build-base \ | ||
| clang15 \ | ||
| llvm15-dev \ | ||
| postgis-dev \ | ||
| postgresql-dev \ | ||
| && git clone --branch v0.8.0 https://github.com/pgvector/pgvector.git /tmp/pgvector \ | ||
| && cd /tmp/pgvector \ | ||
| && make \ | ||
| && make install \ | ||
| && apk add --no-cache postgis \ | ||
| && rm -rf /tmp/pgvector \ | ||
| && apk del .build-deps | ||
|
|
||
| # Use the default entrypoint | ||
| ENTRYPOINT ["docker-entrypoint.sh"] | ||
| CMD ["postgres"] |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2,16 +2,32 @@ name: qcx-stack | |||||
|
|
||||||
| services: | ||||||
| db: | ||||||
| image: postgres:16-alpine | ||||||
| build: | ||||||
| context: . | ||||||
| dockerfile: Dockerfile.db | ||||||
| restart: unless-stopped | ||||||
| environment: | ||||||
| POSTGRES_USER: qcxuser | ||||||
| POSTGRES_PASSWORD: qcxpassword | ||||||
| POSTGRES_DB: qcxdb | ||||||
| POSTGRES_USER: ${POSTGRES_USER:-qcxuser} | ||||||
| POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-qcxpassword} | ||||||
| POSTGRES_DB: ${POSTGRES_DB:-qcxdb} | ||||||
|
Comment on lines
+10
to
+12
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do not ship weak default database credentials in compose interpolation. Defaulting to Suggested fail-fast interpolation- POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-qcxpassword}
+ POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}
@@
- - DATABASE_URL=postgres://${POSTGRES_USER:-qcxuser}:${POSTGRES_PASSWORD:-qcxpassword}`@db`:5432/${POSTGRES_DB:-qcxdb}
+ - DATABASE_URL=postgres://${POSTGRES_USER:-qcxuser}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}`@db`:5432/${POSTGRES_DB:-qcxdb}
@@
- - DATABASE_URL=postgres://${POSTGRES_USER:-qcxuser}:${POSTGRES_PASSWORD:-qcxpassword}`@db`:5432/${POSTGRES_DB:-qcxdb}
+ - DATABASE_URL=postgres://${POSTGRES_USER:-qcxuser}:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}`@db`:5432/${POSTGRES_DB:-qcxdb}Also applies to: 46-47, 73-74 🤖 Prompt for AI Agents |
||||||
| volumes: | ||||||
| - postgres_data:/var/lib/postgresql/data | ||||||
| healthcheck: | ||||||
| test: ["CMD-SHELL", "pg_isready -U qcxuser -d qcxdb"] | ||||||
| test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-qcxuser} -d ${POSTGRES_DB:-qcxdb}"] | ||||||
| interval: 10s | ||||||
| timeout: 5s | ||||||
| retries: 5 | ||||||
|
|
||||||
| qdrant: | ||||||
| image: qdrant/qdrant:latest | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cd /root && find . -name "docker-compose.yaml" -type f 2>/dev/null | head -5Repository: QueueLab/QCX Length of output: 112 🏁 Script executed: find . -name "docker-compose.yaml" -type f 2>/dev/nullRepository: QueueLab/QCX Length of output: 78 🏁 Script executed: cat -n ./docker-compose.yaml | head -30Repository: QueueLab/QCX Length of output: 1031 🏁 Script executed: cat ./docker-compose.yamlRepository: QueueLab/QCX Length of output: 2408 🏁 Script executed: rg "image:" ./docker-compose.yamlRepository: QueueLab/QCX Length of output: 88 Pin Qdrant to an immutable image tag instead of Using Suggested change- image: qdrant/qdrant:latest
+ image: qdrant/qdrant:${QDRANT_IMAGE_TAG:-v1.7.0}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| restart: unless-stopped | ||||||
| ports: | ||||||
| - "6333:6333" | ||||||
| - "6334:6334" | ||||||
| volumes: | ||||||
| - qdrant_data:/qdrant/storage | ||||||
| healthcheck: | ||||||
| test: ["CMD", "curl", "-f", "http://localhost:6333/health"] | ||||||
| interval: 10s | ||||||
| timeout: 5s | ||||||
| retries: 5 | ||||||
|
|
@@ -27,8 +43,10 @@ services: | |||||
| - NODE_ENV=production | ||||||
| - PORT=3000 | ||||||
| - HOSTNAME=0.0.0.0 | ||||||
| - DATABASE_URL=postgres://qcxuser:qcxpassword@db:5432/qcxdb | ||||||
| - DATABASE_URL=postgres://${POSTGRES_USER:-qcxuser}:${POSTGRES_PASSWORD:-qcxpassword}@db:5432/${POSTGRES_DB:-qcxdb} | ||||||
| - QDRANT_URL=http://qdrant:6333 | ||||||
| - EXECUTE_MIGRATIONS=true | ||||||
| # Add other necessary env vars here or use an .env file | ||||||
| depends_on: | ||||||
| db: | ||||||
| condition: service_healthy | ||||||
|
|
@@ -52,10 +70,13 @@ services: | |||||
| environment: | ||||||
| - NODE_ENV=development | ||||||
| - PORT=3000 | ||||||
| - DATABASE_URL=postgres://qcxuser:qcxpassword@db:5432/qcxdb | ||||||
| - DATABASE_URL=postgres://${POSTGRES_USER:-qcxuser}:${POSTGRES_PASSWORD:-qcxpassword}@db:5432/${POSTGRES_DB:-qcxdb} | ||||||
| - QDRANT_URL=http://qdrant:6333 | ||||||
| depends_on: | ||||||
| db: | ||||||
| condition: service_healthy | ||||||
| qdrant: | ||||||
| condition: service_started | ||||||
| volumes: | ||||||
| - .:/app | ||||||
| - node_modules:/app/node_modules | ||||||
|
|
@@ -66,5 +87,6 @@ services: | |||||
|
|
||||||
| volumes: | ||||||
| postgres_data: | ||||||
| qdrant_data: | ||||||
| node_modules: | ||||||
| next_build: | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| CREATE EXTENSION IF NOT EXISTS postgis; | ||
| CREATE EXTENSION IF NOT EXISTS vector; | ||
|
|
||
|
Comment on lines
+2
to
+3
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Line 2 ( Also applies to: 63-63 🤖 Prompt for AI Agents |
||
| CREATE TABLE "calendar_notes" ( | ||
| "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, | ||
| "user_id" uuid NOT NULL, | ||
| "chat_id" uuid, | ||
| "date" timestamp with time zone NOT NULL, | ||
| "content" text NOT NULL, | ||
| "location_tags" jsonb, | ||
| "user_tags" text[], | ||
| "map_feature_id" text, | ||
| "created_at" timestamp with time zone DEFAULT now() NOT NULL, | ||
| "updated_at" timestamp with time zone DEFAULT now() NOT NULL | ||
| ); | ||
| --> statement-breakpoint | ||
| CREATE TABLE "chat_participants" ( | ||
| "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, | ||
| "chat_id" uuid NOT NULL, | ||
| "user_id" uuid NOT NULL, | ||
| "role" text DEFAULT 'collaborator' NOT NULL, | ||
| "created_at" timestamp with time zone DEFAULT now() NOT NULL, | ||
| CONSTRAINT "chat_participants_chat_user_unique" UNIQUE("chat_id","user_id") | ||
| ); | ||
| --> statement-breakpoint | ||
| CREATE TABLE "locations" ( | ||
| "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, | ||
| "user_id" uuid NOT NULL, | ||
| "chat_id" uuid, | ||
| "geojson" jsonb NOT NULL, | ||
| "geometry" geometry(GEOMETRY, 4326), | ||
| "name" text, | ||
| "created_at" timestamp with time zone DEFAULT now() NOT NULL | ||
| ); | ||
| --> statement-breakpoint | ||
| CREATE TABLE "system_prompts" ( | ||
| "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, | ||
| "user_id" uuid NOT NULL, | ||
| "prompt" text NOT NULL, | ||
| "created_at" timestamp with time zone DEFAULT now() NOT NULL, | ||
| "updated_at" timestamp with time zone DEFAULT now() NOT NULL | ||
| ); | ||
| --> statement-breakpoint | ||
| CREATE TABLE "visualizations" ( | ||
| "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, | ||
| "user_id" uuid NOT NULL, | ||
| "chat_id" uuid, | ||
| "type" text DEFAULT 'map_layer' NOT NULL, | ||
| "data" jsonb NOT NULL, | ||
| "geometry" geometry(GEOMETRY, 4326), | ||
| "created_at" timestamp with time zone DEFAULT now() NOT NULL | ||
| ); | ||
| --> statement-breakpoint | ||
| ALTER TABLE "chats" ALTER COLUMN "title" SET DATA TYPE text;--> statement-breakpoint | ||
| ALTER TABLE "chats" ALTER COLUMN "title" SET DEFAULT 'Untitled Chat';--> statement-breakpoint | ||
| ALTER TABLE "chats" ALTER COLUMN "visibility" SET DATA TYPE text;--> statement-breakpoint | ||
| ALTER TABLE "chats" ALTER COLUMN "visibility" SET DEFAULT 'private';--> statement-breakpoint | ||
| ALTER TABLE "messages" ALTER COLUMN "role" SET DATA TYPE text;--> statement-breakpoint | ||
| ALTER TABLE "chats" ADD COLUMN "path" text;--> statement-breakpoint | ||
| ALTER TABLE "chats" ADD COLUMN "share_path" text;--> statement-breakpoint | ||
| ALTER TABLE "chats" ADD COLUMN "shareable_link_id" uuid DEFAULT gen_random_uuid();--> statement-breakpoint | ||
| ALTER TABLE "chats" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;--> statement-breakpoint | ||
|
Comment on lines
+61
to
+62
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid high-lock DDL on Adding Suggested phased approach-ALTER TABLE "chats" ADD COLUMN "shareable_link_id" uuid DEFAULT gen_random_uuid();
-ALTER TABLE "chats" ADD COLUMN "updated_at" timestamp with time zone DEFAULT now() NOT NULL;
-ALTER TABLE "chats" ADD CONSTRAINT "chats_shareable_link_id_unique" UNIQUE("shareable_link_id");
+ALTER TABLE "chats" ADD COLUMN "shareable_link_id" uuid;
+ALTER TABLE "chats" ADD COLUMN "updated_at" timestamp with time zone;
+-- backfill in controlled batches
+ALTER TABLE "chats" ALTER COLUMN "shareable_link_id" SET DEFAULT gen_random_uuid();
+ALTER TABLE "chats" ALTER COLUMN "updated_at" SET DEFAULT now();
+ALTER TABLE "chats" ALTER COLUMN "updated_at" SET NOT NULL;
+-- create unique index concurrently in a separate non-transactional migration, then attach constraintAlso applies to: 79-79 🤖 Prompt for AI Agents |
||
| ALTER TABLE "messages" ADD COLUMN "embedding" vector(1536);--> statement-breakpoint | ||
| ALTER TABLE "messages" ADD COLUMN "location_id" uuid;--> statement-breakpoint | ||
| ALTER TABLE "users" ADD COLUMN "email" text;--> statement-breakpoint | ||
| ALTER TABLE "users" ADD COLUMN "role" text DEFAULT 'viewer';--> statement-breakpoint | ||
| ALTER TABLE "users" ADD COLUMN "selected_model" text;--> statement-breakpoint | ||
| ALTER TABLE "users" ADD COLUMN "system_prompt" text;--> statement-breakpoint | ||
| ALTER TABLE "calendar_notes" ADD CONSTRAINT "calendar_notes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "calendar_notes" ADD CONSTRAINT "calendar_notes_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "chat_participants" ADD CONSTRAINT "chat_participants_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "chat_participants" ADD CONSTRAINT "chat_participants_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "locations" ADD CONSTRAINT "locations_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "locations" ADD CONSTRAINT "locations_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "system_prompts" ADD CONSTRAINT "system_prompts_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "visualizations" ADD CONSTRAINT "visualizations_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "visualizations" ADD CONSTRAINT "visualizations_chat_id_chats_id_fk" FOREIGN KEY ("chat_id") REFERENCES "public"."chats"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint | ||
| ALTER TABLE "messages" ADD CONSTRAINT "messages_location_id_locations_id_fk" FOREIGN KEY ("location_id") REFERENCES "public"."locations"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint | ||
|
Comment on lines
+69
to
+78
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add indexes for new foreign-key columns. The migration adds multiple FKs but no supporting indexes on referencing columns. This will hurt joins and can severely slow parent deletes/updates due to table scans. Index additions to include in this migration set+CREATE INDEX IF NOT EXISTS "calendar_notes_user_id_idx" ON "calendar_notes" ("user_id");
+CREATE INDEX IF NOT EXISTS "calendar_notes_chat_id_idx" ON "calendar_notes" ("chat_id");
+CREATE INDEX IF NOT EXISTS "locations_user_id_idx" ON "locations" ("user_id");
+CREATE INDEX IF NOT EXISTS "locations_chat_id_idx" ON "locations" ("chat_id");
+CREATE INDEX IF NOT EXISTS "system_prompts_user_id_idx" ON "system_prompts" ("user_id");
+CREATE INDEX IF NOT EXISTS "visualizations_user_id_idx" ON "visualizations" ("user_id");
+CREATE INDEX IF NOT EXISTS "visualizations_chat_id_idx" ON "visualizations" ("chat_id");
+CREATE INDEX IF NOT EXISTS "messages_location_id_idx" ON "messages" ("location_id");
+CREATE INDEX IF NOT EXISTS "chat_participants_user_id_idx" ON "chat_participants" ("user_id");🧰 Tools🪛 SQLFluff (4.2.2)[error] 69-69: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 70-70: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 71-71: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 72-72: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 73-73: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 74-74: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 75-75: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 76-76: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 77-77: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) [error] 78-78: ADD CONSTRAINT ... FOREIGN KEY should use NOT VALID to avoid locking the table while validating existing rows. (PG01) 🤖 Prompt for AI Agents |
||
| ALTER TABLE "chats" ADD CONSTRAINT "chats_shareable_link_id_unique" UNIQUE("shareable_link_id");--> statement-breakpoint | ||
| ALTER TABLE "users" ADD CONSTRAINT "users_email_unique" UNIQUE("email"); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cloud Run instructions are missing required Cloud SQL connectivity setup.
The current deploy flow omits attaching the Cloud SQL instance and setting a Cloud Run-compatible
DATABASE_URL, so deployments can start but fail on first DB call.Suggested command-level fix
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 67-67: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
[warning] 71-71: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below
(MD022, blanks-around-headings)
[warning] 74-74: Fenced code blocks should be surrounded by blank lines
(MD031, blanks-around-fences)
🤖 Prompt for AI Agents