Skip to content

[Feat] Render 배포 및 PostgreSQL 마이그레이션#88

Merged
zweadfx merged 5 commits intomainfrom
feat/render-deploy-postgresql
Apr 8, 2026
Merged

[Feat] Render 배포 및 PostgreSQL 마이그레이션#88
zweadfx merged 5 commits intomainfrom
feat/render-deploy-postgresql

Conversation

@zweadfx
Copy link
Copy Markdown
Owner

@zweadfx zweadfx commented Apr 8, 2026

어떤 변경사항인가요?

백엔드를 Render 무료 플랜에 배포하고, 유저 데이터 영속성을 위해 SQLite에서 PostgreSQL로 마이그레이션한다.
Vercel(프론트) + Render(백엔드) 구조로 모바일 포함 전체 환경에서 로그인/회원가입이 동작한다.

작업 상세 내용

  • psycopg2-binary 의존성 추가
  • render.yaml에 PostgreSQL DB 및 누락된 환경변수(SECRET_KEY, DATABASE_URL) 추가
  • postgres://postgresql:// URL 자동 변환 처리 (src/db/database.py)
  • Vercel 환경변수 NEXT_PUBLIC_API_BASE_URL을 Render 배포 URL로 업데이트
  • CORS allow_origins에 Vercel 도메인 추가
  • 배포 후 모바일에서 회원가입/로그인 동작 검증 완료

체크리스트

  • self-test를 수행하였는가?
  • 관련 문서나 주석을 업데이트하였는가?
  • 설정한 코딩 컨벤션을 준수하였는가?

관련 이슈

리뷰 포인트

  • render.yaml Blueprint 설정 — PostgreSQL 인스턴스와 Web Service 연결 구조
  • database.pypostgres://postgresql:// 변환 로직 (Render 제공 URL과 SQLAlchemy 요구사항 불일치 해소)

참고사항 및 스크린샷(선택)

Summary by CodeRabbit

  • New Features

    • Enabled cross-origin requests from production frontend environment.
  • Chores

    • Added database driver dependency for enhanced database support.
    • Updated deployment configuration with database connectivity settings.
    • Updated repository ignore patterns for development tools and documentation.

@zweadfx zweadfx self-assigned this Apr 8, 2026
@zweadfx zweadfx added the feature 새로운 기능 구현 시 사용합니다. label Apr 8, 2026
@zweadfx zweadfx linked an issue Apr 8, 2026 that may be closed by this pull request
7 tasks
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

📝 Walkthrough

Walkthrough

This PR configures Render deployment infrastructure and PostgreSQL migration. Changes include adding the psycopg2-binary dependency, creating a Render-managed PostgreSQL database, normalizing database URLs, updating CORS configuration, and extending gitignore for development tools.

Changes

Cohort / File(s) Summary
Deployment Configuration
.gitignore, render.yaml
Added gitignore entries for AI assistant and code-review tools; created Render database assist-db (PostgreSQL, free plan) and configured assist-api service with SECRET_KEY and DATABASE_URL environment variables.
Dependencies
pyproject.toml
Added psycopg2-binary>=2.9.11 runtime dependency for PostgreSQL support.
Database Connection
src/db/database.py
Implemented URL normalization to convert Render-provided postgres:// URLs to postgresql:// protocol before engine creation; updated SQLite path handling to use normalized URL.
API Configuration
src/main.py
Extended CORS middleware allowed origins to include https://assist-frontend-plum.vercel.app alongside existing http://localhost:3000.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

Poem

🐰 Hopping through configs with database care,
PostgreSQL blooms in the cloud up there,
URLs normalized, CORS aligned just right,
Render and psycopg2 burning bright!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main changes: Render deployment and PostgreSQL migration, which matches the core objectives of moving from SQLite to PostgreSQL and deploying to Render.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/render-deploy-postgresql

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
render.yaml (1)

17-18: Make SECRET_KEY bootstrap-safe in Blueprint deployments.

Because SECRET_KEY is required by src/core/config.py, relying only on manual entry (sync: false) can cause startup failure on fresh deploys. Prefer generateValue: true (or documented mandatory secret injection in deploy steps).
As per coding guidelines "Critical/blocker issues: Correctness issues such as functional bugs" and src/core/config.py requires SECRET_KEY: str with no default.

🔐 Suggested change
       - key: SECRET_KEY
-        sync: false
+        generateValue: true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@render.yaml` around lines 17 - 18, The deployment config marks SECRET_KEY as
sync: false which leaves new Blueprint deploys without a generated value and
causes startup failure because src/core/config.py expects SECRET_KEY: str with
no default; update the render.yaml entry for the SECRET_KEY key to ensure a
value is auto-generated (e.g., replace or add generateValue: true and
remove/avoid sync: false) so Blueprint deployments always get a bootstrap-safe
secret injected before the app starts.
src/main.py (1)

190-193: Move CORS origins to configuration instead of hardcoding.

Current values work, but managing origins in settings (env-driven) will reduce code churn across preview/prod/local environments.

♻️ Suggested refactor
- app.add_middleware(
-     CORSMiddleware,
-     allow_origins=[
-         "http://localhost:3000",
-         "https://assist-frontend-plum.vercel.app",
-     ],
+ app.add_middleware(
+     CORSMiddleware,
+     allow_origins=settings.CORS_ALLOW_ORIGINS,
      allow_methods=["GET", "POST", "OPTIONS"],
      allow_headers=["*"],
  )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main.py` around lines 190 - 193, Replace the hardcoded allow_origins list
in the CORS middleware setup with a configuration-driven value: add a
CORS_ORIGINS (string or list) entry to your settings module (env-driven, e.g.,
comma-separated string parsed into a list) and default it to the current two
origins for safety; then update the CORS middleware call in main.py to use
settings.CORS_ORIGINS instead of the literal list so origins are controlled via
env/config. Ensure the parsing handles empty values and preserves hostnames with
schemes (http/https).
src/db/database.py (1)

15-16: Use SQLAlchemy's make_url() to safely detect and parse SQLite database URLs.

Lines 15–16 use startswith("sqlite") to match any SQLite URL variant but only strip the sqlite:/// prefix. Driver-qualified URLs like sqlite+pysqlite:///path.db will produce malformed paths (e.g., +pysqlite:///path.db), causing Path operations to fail. Similarly, line 23 should check the backend name, not the URL prefix.

Use SQLAlchemy's recommended approach:

from sqlalchemy.engine import make_url

url = make_url(database_url)
if url.get_backend_name() == "sqlite":
    db_path = url.database
    if db_path and db_path != ":memory:":
        Path(db_path).parent.mkdir(parents=True, exist_ok=True)

This correctly handles all SQLite URL forms: sqlite:///path.db, sqlite+pysqlite:///path.db, sqlite:///:memory:, etc.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/db/database.py` around lines 15 - 16, The code currently checks
database_url.startswith("sqlite") and strips "sqlite:///" which fails for
driver-qualified URLs (e.g., "sqlite+pysqlite:///") and breaks Path ops; replace
this logic by parsing the URL with SQLAlchemy's make_url (import make_url from
sqlalchemy.engine), use url.get_backend_name() == "sqlite" to detect SQLite, set
db_path = url.database, and only call Path(db_path).parent.mkdir(...) when
db_path exists and is not ":memory:"; update checks that previously used
database_url.startswith(...) to use get_backend_name() instead.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pyproject.toml`:
- Line 26: The dependency "psycopg2-binary>=2.9.11" in pyproject.toml should be
replaced with the psycopg v3 package; update the dependency to "psycopg[c]>=3.0"
for production (system-linked C libraries) or "psycopg[binary]>=3.0" if you need
a quick binary install, ensuring compatibility with SQLAlchemy 2.x which expects
psycopg v3; update the dependency entry and any related install/readme guidance
accordingly.

---

Nitpick comments:
In `@render.yaml`:
- Around line 17-18: The deployment config marks SECRET_KEY as sync: false which
leaves new Blueprint deploys without a generated value and causes startup
failure because src/core/config.py expects SECRET_KEY: str with no default;
update the render.yaml entry for the SECRET_KEY key to ensure a value is
auto-generated (e.g., replace or add generateValue: true and remove/avoid sync:
false) so Blueprint deployments always get a bootstrap-safe secret injected
before the app starts.

In `@src/db/database.py`:
- Around line 15-16: The code currently checks database_url.startswith("sqlite")
and strips "sqlite:///" which fails for driver-qualified URLs (e.g.,
"sqlite+pysqlite:///") and breaks Path ops; replace this logic by parsing the
URL with SQLAlchemy's make_url (import make_url from sqlalchemy.engine), use
url.get_backend_name() == "sqlite" to detect SQLite, set db_path = url.database,
and only call Path(db_path).parent.mkdir(...) when db_path exists and is not
":memory:"; update checks that previously used database_url.startswith(...) to
use get_backend_name() instead.

In `@src/main.py`:
- Around line 190-193: Replace the hardcoded allow_origins list in the CORS
middleware setup with a configuration-driven value: add a CORS_ORIGINS (string
or list) entry to your settings module (env-driven, e.g., comma-separated string
parsed into a list) and default it to the current two origins for safety; then
update the CORS middleware call in main.py to use settings.CORS_ORIGINS instead
of the literal list so origins are controlled via env/config. Ensure the parsing
handles empty values and preserves hostnames with schemes (http/https).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7f354250-0bff-4bc7-87da-b0b94e2c4b50

📥 Commits

Reviewing files that changed from the base of the PR and between 17d019c and 743710d.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • .gitignore
  • pyproject.toml
  • render.yaml
  • src/db/database.py
  • src/main.py

@zweadfx zweadfx merged commit e0b3ad1 into main Apr 8, 2026
2 checks passed
@zweadfx zweadfx deleted the feat/render-deploy-postgresql branch April 8, 2026 14:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature 새로운 기능 구현 시 사용합니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] Render 배포 + PostgreSQL 마이그레이션

1 participant