feat: add Docker Compose for single-command local development - #28
feat: add Docker Compose for single-command local development#28AtherBilal wants to merge 1 commit into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Docker Compose-based local development for the core stack: root Changes
Sequence Diagram(s)sequenceDiagram
rect rgba(240,248,255,0.5)
participant Dev as "Developer"
end
rect rgba(224,255,255,0.5)
participant DC as "Docker Compose"
participant API as "api (Python)"
participant WEB as "web (Vite)"
participant SB as "Supabase"
end
Dev->>DC: docker compose up
DC->>API: build & start container
API->>API: serve healthcheck endpoint
DC->>WEB: wait for API healthy → start web
Dev->>WEB: open frontend (http://localhost:3000)
WEB->>API: HTTP API requests
API->>SB: DB / Auth requests
SB-->>API: responses
API-->>WEB: API responses
WEB-->>Dev: render UI
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
docker-compose.yml (1)
11-16: Health check implementation is functional but consider a lighter alternative.The current healthcheck uses Python to import httpx and make an HTTP request. While functional (httpx is confirmed in
requirements.txt), this approach:
- Spawns a Python interpreter every 10 seconds
- Adds overhead compared to native tools
⚡ Optional: Use curl for lighter health checks
If you want to reduce overhead, install
curlin the Dockerfile and use it for health checks:In core-api/Dockerfile:
FROM python:3.13-slim +RUN apt-get update && apt-get install -y --no-install-recommends curl && rm -rf /var/lib/apt/lists/* + WORKDIR /appIn docker-compose.yml:
healthcheck: - test: ["CMD", "python", "-c", "import httpx; httpx.get('http://localhost:8000/')"] + test: ["CMD", "curl", "-f", "http://localhost:8000/"] interval: 10sHowever, the current httpx-based approach works fine for development and avoids adding dependencies to the image.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docker-compose.yml` around lines 11 - 16, Replace the Python/httpx healthcheck to a lighter curl-based check: update the docker-compose healthcheck "test" to call curl with a fail-on-error flag (e.g., curl -f http://localhost:8000/) and ensure the image contains curl by adding its installation to the Dockerfile used to build the service (install curl in the Dockerfile build steps for the core API image). Locate the healthcheck block in docker-compose.yml (the test key using python -c import httpx...) and the service Dockerfile (add package install for curl), then update the test to use curl so the container runs a native binary instead of spawning Python every interval.core-web/Dockerfile (1)
1-14: LGTM! Consider adding a non-root user for defense in depth.The Dockerfile uses
npm cifor reproducible installs and correctly layers package files before application code for build caching.Similar to the API Dockerfile, running as root is acceptable for development but adding a non-root user would be a good practice:
🔒 Optional: Add non-root user
FROM node:22-slim WORKDIR /app +# Create non-root user +RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app +USER appuser + # Install dependencies COPY package.json package-lock.json ./ RUN npm ciNote: Ensure volume mounts use matching UID/GID to avoid permission issues.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-web/Dockerfile` around lines 1 - 14, Add a non-root user in the Dockerfile to run the app for defense-in-depth: create a dedicated user and group (e.g., app user), chown the WORKDIR (/app) and node_modules after running npm ci, and switch to that user before CMD (ensure EXPOSE and CMD remain unchanged). Use a fixed UID/GID or make them configurable via build args to help match host volume mounts and avoid permission issues when mounting volumes. Ensure commands that need root (install steps) run before switching to the non-root user.core-api/Dockerfile (1)
1-14: LGTM! Consider adding a non-root user for defense in depth.The Dockerfile correctly installs dependencies before copying code, enabling layer caching. The
CMDrunsdev.py, which starts uvicorn with hot reload (confirmed by context snippet showingreload=Trueindev.py).For development containers, running as root is common but not ideal. Consider adding a non-root user as a good practice:
🔒 Optional: Add non-root user
FROM python:3.13-slim WORKDIR /app +# Create non-root user +RUN useradd -m -u 1000 appuser && chown -R appuser:appuser /app +USER appuser + # Install dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txtNote: If added, ensure volume mounts use matching UID/GID on the host to avoid permission issues.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-api/Dockerfile` around lines 1 - 14, Add a non-root user to the Dockerfile: create a group/user after using the python:3.13-slim base image, chown the WORKDIR (/app) and any installed files to that user, and switch to that user before the CMD ["python", "dev.py"] is executed; ensure the user creation and chown steps occur after COPY and pip install to keep layer caching benefits and note that host volume mounts may need matching UID/GID to avoid permission issues.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@core-api/Dockerfile`:
- Around line 1-14: Add a non-root user to the Dockerfile: create a group/user
after using the python:3.13-slim base image, chown the WORKDIR (/app) and any
installed files to that user, and switch to that user before the CMD ["python",
"dev.py"] is executed; ensure the user creation and chown steps occur after COPY
and pip install to keep layer caching benefits and note that host volume mounts
may need matching UID/GID to avoid permission issues.
In `@core-web/Dockerfile`:
- Around line 1-14: Add a non-root user in the Dockerfile to run the app for
defense-in-depth: create a dedicated user and group (e.g., app user), chown the
WORKDIR (/app) and node_modules after running npm ci, and switch to that user
before CMD (ensure EXPOSE and CMD remain unchanged). Use a fixed UID/GID or make
them configurable via build args to help match host volume mounts and avoid
permission issues when mounting volumes. Ensure commands that need root (install
steps) run before switching to the non-root user.
In `@docker-compose.yml`:
- Around line 11-16: Replace the Python/httpx healthcheck to a lighter
curl-based check: update the docker-compose healthcheck "test" to call curl with
a fail-on-error flag (e.g., curl -f http://localhost:8000/) and ensure the image
contains curl by adding its installation to the Dockerfile used to build the
service (install curl in the Dockerfile build steps for the core API image).
Locate the healthcheck block in docker-compose.yml (the test key using python -c
import httpx...) and the service Dockerfile (add package install for curl), then
update the test to use curl so the container runs a native binary instead of
spawning Python every interval.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b90f745e-c4e1-4464-9942-3d30b2ade14e
📒 Files selected for processing (7)
.env.exampleREADME.mdcore-api/.dockerignorecore-api/Dockerfilecore-web/.dockerignorecore-web/Dockerfiledocker-compose.yml
6e84e7b to
56b763e
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.env.example:
- Around line 29-30: Update the .env.example to document that VITE_API_URL needs
to match any custom CORE_API_PORT; specifically, add an inline comment next to
VITE_API_URL explaining that if CORE_API_PORT is changed the host:port in
VITE_API_URL must be updated (show a short example like
VITE_API_URL=http://localhost:<CORE_API_PORT>) so users know to keep
VITE_API_URL and CORE_API_PORT in sync.
- Around line 26-30: Add a new environment variable entry and brief note to the
.env.example explaining ALLOWED_ORIGINS_ENV so users running the frontend on
non-default ports will add the matching origin for CORS; reference the existing
FRONTEND_URL variable and show that ALLOWED_ORIGINS_ENV should contain a
comma-separated list of allowed origins (e.g., http://localhost:3000) to be used
by the API CORS configuration.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 05cb1c73-afe9-45f4-a9d1-8cfa573f0ef0
📒 Files selected for processing (7)
.env.exampleREADME.mdcore-api/.dockerignorecore-api/Dockerfilecore-web/.dockerignorecore-web/Dockerfiledocker-compose.yml
✅ Files skipped from review due to trivial changes (6)
- core-api/.dockerignore
- core-web/.dockerignore
- core-api/Dockerfile
- core-web/Dockerfile
- README.md
- docker-compose.yml
b8ba9e4 to
fa056ab
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (3)
core-api/Dockerfile (2)
5-7: Consider pinning pip version for reproducible builds.While using
--no-cache-diris appropriate, consider upgrading and pinning pip to avoid version-dependent behavior across builds.📦 Proposed improvement
# Install dependencies +RUN pip install --upgrade pip==24.3.1 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-api/Dockerfile` around lines 5 - 7, Pin and upgrade pip before installing requirements to ensure reproducible builds: add a step that upgrades pip to a specific version (e.g., pip==23.2.1) prior to running the existing RUN pip install --no-cache-dir -r requirements.txt command so the build always uses the pinned pip; reference the existing COPY requirements.txt and the pip install --no-cache-dir -r requirements.txt line when making this change.
1-3: Consider adding a non-root user for better security posture.Even for development containers, running as root violates the principle of least privilege. Files written by the hot-reload server will be owned by root, which can cause permission issues on the host.
🔒 Proposed fix to add non-root user
FROM python:3.13-slim +RUN groupadd -r appuser && useradd -r -g appuser appuser + WORKDIR /app + +RUN chown appuser:appuser /appThen before the CMD instruction:
EXPOSE 8000 +USER appuser + # Development server with hot reload CMD ["python", "dev.py"]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-api/Dockerfile` around lines 1 - 3, Add a non-root user in the Dockerfile: create a dedicated user and group, chown the WORKDIR (/app) to that user, and switch to it before CMD so the container does not run as root; update the Dockerfile around the existing FROM python:3.13-slim and WORKDIR /app entries to add the user/group creation, chown of /app, and a USER instruction so the hot-reload server and any files it writes are owned by the non-root user.core-web/Dockerfile (1)
1-3: Consider adding a non-root user for better security posture.Similar to the API container, running as root violates the principle of least privilege. Files created by Vite's dev server and hot-reload will be owned by root.
🔒 Proposed fix to add non-root user
FROM node:22-slim +RUN groupadd -r appuser && useradd -r -g appuser appuser + WORKDIR /app + +RUN chown appuser:appuser /appThen before the CMD instruction:
EXPOSE 3000 +USER appuser + # Development server with hot reload CMD ["npm", "run", "dev", "--", "--host"]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@core-web/Dockerfile` around lines 1 - 3, The Dockerfile currently runs as root; add a non-root user and switch to it before CMD to follow least privilege: create a group/user (e.g., app or node), set ownership of WORKDIR (/app) to that user (chown), set appropriate permissions, and add a USER instruction so the container runs as the new non-root user; ensure these changes occur after installing deps and before the final CMD/ENTRYPOINT so Vite-created files are owned by the non-root user.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@core-api/Dockerfile`:
- Around line 5-7: Pin and upgrade pip before installing requirements to ensure
reproducible builds: add a step that upgrades pip to a specific version (e.g.,
pip==23.2.1) prior to running the existing RUN pip install --no-cache-dir -r
requirements.txt command so the build always uses the pinned pip; reference the
existing COPY requirements.txt and the pip install --no-cache-dir -r
requirements.txt line when making this change.
- Around line 1-3: Add a non-root user in the Dockerfile: create a dedicated
user and group, chown the WORKDIR (/app) to that user, and switch to it before
CMD so the container does not run as root; update the Dockerfile around the
existing FROM python:3.13-slim and WORKDIR /app entries to add the user/group
creation, chown of /app, and a USER instruction so the hot-reload server and any
files it writes are owned by the non-root user.
In `@core-web/Dockerfile`:
- Around line 1-3: The Dockerfile currently runs as root; add a non-root user
and switch to it before CMD to follow least privilege: create a group/user
(e.g., app or node), set ownership of WORKDIR (/app) to that user (chown), set
appropriate permissions, and add a USER instruction so the container runs as the
new non-root user; ensure these changes occur after installing deps and before
the final CMD/ENTRYPOINT so Vite-created files are owned by the non-root user.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8fb7c640-d790-4246-a0bb-5e1e7bdd5b20
📒 Files selected for processing (7)
.env.exampleREADME.mdcore-api/.dockerignorecore-api/Dockerfilecore-web/.dockerignorecore-web/Dockerfiledocker-compose.yml
✅ Files skipped from review due to trivial changes (4)
- core-web/.dockerignore
- core-api/.dockerignore
- docker-compose.yml
- README.md
fa056ab to
5682361
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (1)
.env.example (1)
24-30:⚠️ Potential issue | 🟠 MajorDocument port overrides and URL sync in the env template.
Line 28 (
FRONTEND_URL) and Line 29 (VITE_API_URL) currently assume default ports, but the PR advertises configurable ports. AddCORE_API_PORT/CORE_WEB_PORTand explicit sync notes so overrides don’t silently break frontend↔API communication.Suggested update
# ------------------------------------------------------------------------------ # [REQUIRED] API # ------------------------------------------------------------------------------ API_ENV=development DEBUG=false +# Compose host port overrides +CORE_API_PORT=8000 +CORE_WEB_PORT=3000 + +# Keep this in sync with CORE_WEB_PORT when overriding FRONTEND_URL=http://localhost:3000 +# Keep this in sync with CORE_API_PORT when overriding VITE_API_URL=http://localhost:8000/api🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.example around lines 24 - 30, Add explicit CORE_API_PORT and CORE_WEB_PORT entries to the env template and update the FRONTEND_URL and VITE_API_URL descriptions to warn that changing ports requires updating both URLs (or using the CORE_*_PORT variables) so frontend↔API links remain in sync; specifically add CORE_API_PORT and CORE_WEB_PORT variables, and modify the FRONTEND_URL and VITE_API_URL lines (and their comments) to explain how to construct/sync them when overriding ports so developers don't accidentally point the frontend at the wrong port.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In @.env.example:
- Around line 24-30: Add explicit CORE_API_PORT and CORE_WEB_PORT entries to the
env template and update the FRONTEND_URL and VITE_API_URL descriptions to warn
that changing ports requires updating both URLs (or using the CORE_*_PORT
variables) so frontend↔API links remain in sync; specifically add CORE_API_PORT
and CORE_WEB_PORT variables, and modify the FRONTEND_URL and VITE_API_URL lines
(and their comments) to explain how to construct/sync them when overriding ports
so developers don't accidentally point the frontend at the wrong port.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 96b70e1c-75ca-462d-b9cc-7e7628ced497
📒 Files selected for processing (7)
.env.exampleREADME.mdcore-api/.dockerignorecore-api/Dockerfilecore-web/.dockerignorecore-web/Dockerfiledocker-compose.yml
✅ Files skipped from review due to trivial changes (5)
- core-web/.dockerignore
- core-api/.dockerignore
- core-api/Dockerfile
- core-web/Dockerfile
- README.md
🚧 Files skipped from review as they are similar to previous changes (1)
- docker-compose.yml
Self-hosters and contributors can now run both services with `docker compose up` instead of installing Node, Python, and uv separately. Includes Dockerfiles for core-api and core-web with volume mounts for hot reload during development. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5682361 to
7b4d158
Compare
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
.env.example (4)
19-21: Consider using variable substitution to eliminate duplication.Lines 20-21 require duplicating the Supabase URL and anon key (once for the backend, once for the frontend). This introduces maintenance burden and risk of mismatch. Docker Compose supports variable substitution:
♻️ Proposed refactor using variable substitution
# Frontend Supabase config (must match the values above) -VITE_SUPABASE_URL=https://your-project.supabase.co -VITE_SUPABASE_ANON_KEY=your-anon-key +VITE_SUPABASE_URL=${SUPABASE_URL} +VITE_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}This ensures the frontend always uses the backend's values and eliminates the "must match" constraint.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.example around lines 19 - 21, The frontend .env entries VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are duplicating backend values; change them to use environment variable substitution (e.g., set VITE_SUPABASE_URL=${SUPABASE_URL} and VITE_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}) so Docker Compose / env file resolution provides the backend values automatically; update .env.example to demonstrate the substitution and ensure your compose/service config exposes SUPABASE_URL and SUPABASE_ANON_KEY to the frontend.
1-8: Document the namespace pollution inherent in the shared.envapproach.The Docker Compose configuration loads the entire
.envfile into both theapiandwebcontainers without filtering. This means:
- The web container receives backend-only secrets (e.g.,
SUPABASE_SERVICE_ROLE_KEY,R2_SECRET_ACCESS_KEY)- The API container receives frontend-only variables (e.g.,
VITE_*variables)While not functionally broken for development (unused variables are ignored, and Vite only exposes
VITE_-prefixed variables to the browser), this creates confusion about which service uses which variables and complicates security audits.Consider documenting this limitation in the header comments, or refactor
docker-compose.ymlto explicitly declare each service's required variables using theenvironment:key instead ofenv_file:for clearer separation.Alternative approach using explicit environment mapping
In
docker-compose.yml:services: api: environment: - SUPABASE_URL=${SUPABASE_URL} - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY} - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY} # ... other API-only vars web: environment: - VITE_SUPABASE_URL=${VITE_SUPABASE_URL} - VITE_API_URL=${VITE_API_URL} # ... other VITE_ varsThis approach makes dependencies explicit and prevents namespace pollution.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.example around lines 1 - 8, Add a short note to the top of .env.example explaining that using a shared .env with docker-compose env_file loads all variables into every service (causing namespace pollution) and that backend-only secrets (e.g., SUPABASE_SERVICE_ROLE_KEY, R2_SECRET_ACCESS_KEY) may end up in the web container while frontend VITE_* variables are available to the API; suggest either documenting this limitation or refactoring docker-compose.yml to map each service's variables explicitly via the environment: key (listing API-only vars like SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY and web-only VITE_* vars) to avoid accidental exposure and make intent explicit.
30-31:VITE_API_URLis misplaced in the API section.
VITE_API_URLis a frontend environment variable (theVITE_prefix means it's exposed to the browser by Vite). Placing it under[REQUIRED] APIis confusing since it belongs to the web service. Consider moving it to a[REQUIRED] Frontendsubsection or grouping it with the otherVITE_variables.♻️ Proposed reorganization
# ------------------------------------------------------------------------------ # [REQUIRED] API # ------------------------------------------------------------------------------ API_ENV=development DEBUG=false # If you override CORE_WEB_PORT, update this to match (e.g. http://localhost:4000) FRONTEND_URL=http://localhost:3000 + +# ------------------------------------------------------------------------------ +# [REQUIRED] Frontend +# ------------------------------------------------------------------------------ # If you override CORE_API_PORT, update this to match (e.g. http://localhost:9000/api) VITE_API_URL=http://localhost:8000/api + +# ------------------------------------------------------------------------------ +# [REQUIRED] CORS +# ------------------------------------------------------------------------------ # Comma-separated CORS origins. Only needed if running on non-default ports. # ALLOWED_ORIGINS_ENV=http://localhost:4000🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.example around lines 30 - 31, VITE_API_URL is a frontend-specific env var (Vite-exposed) but is currently listed under the [REQUIRED] API section; move the VITE_API_URL entry out of the API block and into a new or existing [REQUIRED] Frontend subsection (or alongside other VITE_ variables), update its explanatory comment to mention it should match CORE_API_PORT if overridden, and ensure other VITE_* variables are grouped together so frontend-related settings are not mixed with backend/API settings.
28-29: Add clarification about port differences between Docker and non-Docker setups.The root
.env.exampledeclaresFRONTEND_URL=http://localhost:3000for Docker Compose, whilecore-api/.env.exampledeclaresFRONTEND_URL=http://localhost:5173for native Vite dev server. This difference may confuse developers switching between setup modes. Add a note in the root.env.exampleto clarify:Proposed clarification
# If you override CORE_WEB_PORT, update this to match (e.g. http://localhost:4000) +# Note: Non-Docker setups use port 5173 (native Vite), Docker uses 3000 FRONTEND_URL=http://localhost:3000🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.example around lines 28 - 29, Update the root .env.example comment next to FRONTEND_URL to explicitly note the port difference between Docker Compose and native Vite dev mode: explain that Docker Compose maps the frontend to CORE_WEB_PORT (default http://localhost:3000) while developing natively Vite uses port 5173 (see core-api/.env.example), and remind developers to update FRONTEND_URL to match if they override CORE_WEB_PORT or run the Vite dev server locally. Include references to FRONTEND_URL, CORE_WEB_PORT, and core-api/.env.example so readers know where to look and what to change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.env.example:
- Around line 28-33: The comment points out that when overriding CORE_WEB_PORT
or CORE_API_PORT the example envs FRONTEND_URL and VITE_API_URL must be
updated—and you must also remind users to update ALLOWED_ORIGINS_ENV so the new
frontend origin is allowed via CORS; update the .env.example comments around
FRONTEND_URL, VITE_API_URL and ALLOWED_ORIGINS_ENV to explicitly state that
ALLOWED_ORIGINS_ENV should be updated to include the new FRONTEND_URL (or
matching origin) whenever CORE_WEB_PORT/CORE_API_PORT are changed and show a
short example of the comma-separated format using the updated port.
---
Nitpick comments:
In @.env.example:
- Around line 19-21: The frontend .env entries VITE_SUPABASE_URL and
VITE_SUPABASE_ANON_KEY are duplicating backend values; change them to use
environment variable substitution (e.g., set VITE_SUPABASE_URL=${SUPABASE_URL}
and VITE_SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}) so Docker Compose / env file
resolution provides the backend values automatically; update .env.example to
demonstrate the substitution and ensure your compose/service config exposes
SUPABASE_URL and SUPABASE_ANON_KEY to the frontend.
- Around line 1-8: Add a short note to the top of .env.example explaining that
using a shared .env with docker-compose env_file loads all variables into every
service (causing namespace pollution) and that backend-only secrets (e.g.,
SUPABASE_SERVICE_ROLE_KEY, R2_SECRET_ACCESS_KEY) may end up in the web container
while frontend VITE_* variables are available to the API; suggest either
documenting this limitation or refactoring docker-compose.yml to map each
service's variables explicitly via the environment: key (listing API-only vars
like SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY and web-only
VITE_* vars) to avoid accidental exposure and make intent explicit.
- Around line 30-31: VITE_API_URL is a frontend-specific env var (Vite-exposed)
but is currently listed under the [REQUIRED] API section; move the VITE_API_URL
entry out of the API block and into a new or existing [REQUIRED] Frontend
subsection (or alongside other VITE_ variables), update its explanatory comment
to mention it should match CORE_API_PORT if overridden, and ensure other VITE_*
variables are grouped together so frontend-related settings are not mixed with
backend/API settings.
- Around line 28-29: Update the root .env.example comment next to FRONTEND_URL
to explicitly note the port difference between Docker Compose and native Vite
dev mode: explain that Docker Compose maps the frontend to CORE_WEB_PORT
(default http://localhost:3000) while developing natively Vite uses port 5173
(see core-api/.env.example), and remind developers to update FRONTEND_URL to
match if they override CORE_WEB_PORT or run the Vite dev server locally. Include
references to FRONTEND_URL, CORE_WEB_PORT, and core-api/.env.example so readers
know where to look and what to change.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1b0aa4ff-29aa-4a29-9e8d-f2413a09b628
📒 Files selected for processing (7)
.env.exampleREADME.mdcore-api/.dockerignorecore-api/Dockerfilecore-web/.dockerignorecore-web/Dockerfiledocker-compose.yml
✅ Files skipped from review due to trivial changes (5)
- core-web/.dockerignore
- core-api/.dockerignore
- README.md
- core-api/Dockerfile
- docker-compose.yml
🚧 Files skipped from review as they are similar to previous changes (1)
- core-web/Dockerfile
| # If you override CORE_WEB_PORT, update this to match (e.g. http://localhost:4000) | ||
| FRONTEND_URL=http://localhost:3000 | ||
| # If you override CORE_API_PORT, update this to match (e.g. http://localhost:9000/api) | ||
| VITE_API_URL=http://localhost:8000/api | ||
| # Comma-separated CORS origins. Only needed if running on non-default ports. | ||
| # ALLOWED_ORIGINS_ENV=http://localhost:4000 |
There was a problem hiding this comment.
Port override guidance is incomplete: ALLOWED_ORIGINS_ENV must also be synced.
The inline comments explain that FRONTEND_URL must match CORE_WEB_PORT and VITE_API_URL must match CORE_API_PORT, but there's no guidance that ALLOWED_ORIGINS_ENV must ALSO be updated when CORE_WEB_PORT changes (to allow the new frontend origin through CORS). This creates a broken configuration path.
📝 Proposed documentation update
# If you override CORE_WEB_PORT, update this to match (e.g. http://localhost:4000)
FRONTEND_URL=http://localhost:3000
# If you override CORE_API_PORT, update this to match (e.g. http://localhost:9000/api)
VITE_API_URL=http://localhost:8000/api
-# Comma-separated CORS origins. Only needed if running on non-default ports.
+# Comma-separated CORS origins. Must include FRONTEND_URL when overriding CORE_WEB_PORT.
+# Example: If CORE_WEB_PORT=4000, set ALLOWED_ORIGINS_ENV=http://localhost:4000
# ALLOWED_ORIGINS_ENV=http://localhost:4000🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.env.example around lines 28 - 33, The comment points out that when
overriding CORE_WEB_PORT or CORE_API_PORT the example envs FRONTEND_URL and
VITE_API_URL must be updated—and you must also remind users to update
ALLOWED_ORIGINS_ENV so the new frontend origin is allowed via CORS; update the
.env.example comments around FRONTEND_URL, VITE_API_URL and ALLOWED_ORIGINS_ENV
to explicitly state that ALLOWED_ORIGINS_ENV should be updated to include the
new FRONTEND_URL (or matching origin) whenever CORE_WEB_PORT/CORE_API_PORT are
changed and show a short example of the comma-separated format using the updated
port.



Summary
Getting Core running locally currently requires installing Node.js, Python, uv, and managing two separate processes. This PR adds Docker Compose so the entire stack comes up with a single command and a single env file — no language runtimes needed on the host.
Changes
.env.example— single env file for both API and frontend (replaces the need to configure two separate files)docker-compose.yml— two-service dev setup with health checks, volume mounts, and configurable portscore-api/Dockerfile— Python 3.13 slim image running uvicorn with hot reloadcore-web/Dockerfile— Node 22 slim image running Vite dev server with hot reloadcore-api/.dockerignore/core-web/.dockerignore— keeps images leanREADME.md— Docker Compose section added to Quick StartDetails
.env— one file at the repo root configures both services. The per-service env files (core-api/.env,core-web/.env) still work for non-Docker setupsCORE_API_PORT=9000 CORE_WEB_PORT=4000 docker compose upcore-image-proxyis a Cloudflare Worker and not needed for local dev (the API falls back to presigned R2 URLs)Test plan
docker compose upstarts both services, API healthy before web startsCORE_API_PORT=9000 docker compose updocker compose downcleans up cleanly🤖 Generated with Claude Code
Summary by CodeRabbit
Documentation
Chores