-
Notifications
You must be signed in to change notification settings - Fork 56
feat(docker): rewrite build and deployment pipeline #723
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
Conversation
- Updated `.dockerignore` to exclude node_modules, env files, logs, and build artifacts - Split Dockerfile into copy‑and‑install stages for improved layer caching - Added `data-restore.sh`, sample data archive, and `start.sh` entrypoint that: * Waits for Postgres/Vespa * Runs migrations only on first launch * Starts the application - Replaced old compose file with `docker-compose.prod.yml`: * Includes init containers for app‑storage, Prometheus, Grafana, Vespa, Loki, Promtail * Adds comprehensive health‑checks, ports, and user‑group settings - Updated `promtail-config.yaml` to capture both application and Docker container logs - Added `setup-deployment.sh` to: * Auto‑create required data directories * Set permissions via Docker containers (no sudo) * Inject Docker group ID for Promtail socket access * Print monitoring instructions
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds a portable one‑click deployment stack (CPU/GPU) with compose files, infra and app orchestration scripts, packaging/export helpers, Grafana/Loki/Prometheus provisioning and dashboards, a GPU Vespa Dockerfile, Dockerfile refactor and runtime start script, updated ignore rules, Vertex AI timeout/retry handling, and docs/navigation entry. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Container
participant S as start.sh
participant DB as Postgres (xyne-db)
participant V as Vespa (config server)
participant App as Bun server
C->>S: run start.sh (CMD)
S->>S: source /usr/src/app/server/.env
loop wait for DB
S->>DB: simple DB query (via Bun/Node)
DB-->>S: success/fail
end
loop wait for Vespa
S->>V: GET /state/v1/health
V-->>S: healthy/unhealthy
end
alt first-run (no .xyne_initialized)
S->>App: bun run generate && bun run migrate
S->>V: deploy Vespa (deploy-docker.sh)
S->>S: touch .xyne_initialized
else subsequent runs
S->>S: skip init
end
S->>App: exec bun server.ts
sequenceDiagram
autonumber
participant U as User
participant D as deploy.sh
participant DC as Docker Compose
participant Infra as Infrastructure (Prometheus/Grafana/Loki/Vespa/DB)
participant App as Application (xyne)
U->>D: ./deploy.sh start [--force-gpu|--force-cpu]
D->>D: detect_gpu_support() & setup_environment()
D->>DC: docker-compose -f infrastructure up -d
DC-->>Infra: start infra services (init containers prepare volumes)
D->>DC: docker-compose -f app up -d
DC-->>App: start app (depends on infra healthchecks)
U->>D: update-app / update-infra
D->>DC: build/pull and recreate selected services
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches🧪 Generate unit tests
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @shivamashtikar, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
I've undertaken a significant rewrite of the Docker build and deployment pipeline to enhance efficiency, robustness, and ease of use. This refactor focuses on optimizing Docker image builds through better layer caching and more comprehensive .dockerignore
rules. I've introduced a new orchestrated startup script (start.sh
) within the application container to manage service dependencies and perform first-time setup tasks like migrations. The docker-compose.prod.yml
has been overhauled to include dedicated initialization containers for volume setup, robust health checks, and improved logging configurations for all services. Additionally, the setup-deployment.sh
script has been updated to automate directory creation and permission management without requiring sudo
, and to provide better guidance for log monitoring.
Highlights
- Comprehensive .dockerignore updates: The
.dockerignore
file has been significantly expanded to exclude a wider range of unnecessary files and directories from the Docker build context, including node_modules, various .env files, large data directories, build artifacts, logs, OS files, editor files, and test artifacts. This reduces image size and build times. - Dockerfile optimization and new script integration: The
Dockerfile
has been refactored to optimize layer caching by copying package files and installing dependencies before copying the full source code. It also now includes steps to copy and make executable new data restoration and startup scripts. - Intelligent application startup with start.sh: A new
start.sh
script has been introduced as the container's entrypoint. This script intelligently handles service dependencies by waiting for PostgreSQL and Vespa to be ready, performs database migrations and Vespa schema deployment only on the first launch, and then starts the application. - Enhanced Docker Compose for production: The
docker-compose.prod.yml
file has been completely rewritten to includebusybox
init containers for robust volume initialization and permission setting for various services (app, Prometheus, Loki, Promtail). It also adds comprehensive health checks, refined port mappings, and user/group settings for all services. - Improved log collection with Promtail: The
promtail-config.yaml
has been updated to collect logs not only from the application's log files but also directly from Docker container logs using Docker service discovery, providing a more complete logging solution. - Automated deployment setup and permissions management: The
setup-deployment.sh
script now automatically creates required data directories and sets their permissions using Docker containers, eliminating the need forsudo
. It also detects and injects the Docker group ID for Promtail's socket access and provides clear instructions for monitoring.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
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.
Code Review
This pull request is a major and impressive overhaul of the project's Docker build and deployment pipeline. It introduces best practices like multi-stage builds for better caching, healthchecks for service reliability, and init containers for managing permissions without requiring sudo
. The new start.sh
script robustly handles service dependencies, and the logging setup with Promtail/Loki is much more advanced.
My review focuses on a few critical areas to further improve security and correctness: preventing secrets from being baked into the image, correcting a port mismatch in the application service, and fixing potential bugs in the startup script related to environment variable parsing and database migrations. I've also included suggestions for improving image tagging practices for production stability. Overall, this is a fantastic contribution that significantly matures the project's deployment strategy.
- Introduce quick-export.sh to build Xyne Docker image, bundle configs, and create a portable package with import.sh, deploy.sh, and README - Generate archive for easy transfer to another machine - Update .gitignore to exclude generated portable packages (xyne-portable-*) and data/app-assets/ - Simplify Xyne export/import without requiring root privileges, handling image export, permissions, and cleanup automatically
…Prometheus scrape target - Add volume mount for uploaded video assets (`./data/app-assets:/usr/src/app/server/dist/assets/videos`) - Remove default fallback for Grafana `user`, forcing use of `DOCKER_UID`/`DOCKER_GID` - Correct Prometheus scrape target from port 3001 to port 3000 to collect metrics from the application endpoint
- Build local `xyne-vespa-gpu` image from `Dockerfile-vespa-gpu` - Update `docker-compose.prod.yml` to expose ports without `${VESPA_PORT}` and reserve GPU devices in the deploy section - Update `quick-export.sh` to build, export, and load the GPU image, remove the remote `vespaengine/vespa` pull, copy the new Dockerfile into the export, and print GPU‑related notes in the deployment output
- Introduce `--no-export` to skip image export and file copying - Add `--force-build` to rebuild GPU image even if unchanged - Provide `cleanup` flag to remove temporary artifacts after export - Expand help output for new flags - Conditionally build Vespa GPU image only if newer or missing - Rewrite final output to give deployment instructions for the two modes - Comment out host‑exposed ports in production compose to prevent accidental exposure
- Remove old docker‑compose.gpu.yml override file - Merge GPU‑specific configuration into docker‑compose.prod.yml - Add `runtime: nvidia` to the Vespa service - Set `NVIDIA_VISIBLE_DEVICES` and `NVIDIA_DRIVER_CAPABILITIES` env vars - Update commented port mapping to use a different default port - Centralise GPU support in the production compose file for simplified deployment.
…ction - Add comprehensive portable deployment system in deployment/portable/ - Implement automatic GPU/CPU detection for optimal Vespa configuration - Create modular Docker Compose architecture for efficient app updates - Add database migration persistence with Drizzle ORM support - Include complete monitoring stack (Grafana, Prometheus, Loki, Promtail) - Add canvas native dependencies to Dockerfile for image processing - Create deployment documentation and user guides - Implement cross-platform compatibility (Linux, macOS, Windows WSL2) Key features: - One-click deployment with ./deploy.sh start - Fast app-only updates (~30s vs 3+ min full restart) - Auto-detection: GPU-accelerated or CPU-only Vespa - Persistent migrations across container rebuilds - Built-in export/import for easy machine transfers - Production-ready with health checks and monitoring 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Add `EXPOSE 3001` to the Dockerfile and remove the previous `80/tcp` expose - Update `docker‑compose.app.yml` to map the new port (`3001:3001`) alongside the existing `3000:80` mapping - Switch Prometheus scrape target from `localhost:3000` to the app’s service `xyne-app:3001` - Clarify that port handling is now delegated to the compose configuration
…scripts - Trim compose file to core services (app, prometheus, grafana, vespa, loki, postgres, promtail) - Remove auxiliary init containers, Ollama stack, and custom Docker‑user logic - Switch to explicit, stable image tags - Move volumes to project‑relative paths - Drop unnecessary health‑checks - Simplify user/group IDs to standard users (e.g., 472 for Grafana, 1000 for Vespa) - Update Loki/Promtail configs to match new volume paths - Delete redundant quick‑export script - Rework `setup‑deployment.sh` to use relative data directories, eliminating legacy directory handling and env‑file manipulation - Improve portability and reduce reliance on privileged Docker runtime features
4aab632
to
2212c39
Compare
…nt, simplify start.sh - Remove automatic COPY of `.env*` files from Docker image - Update `vertex_ai.ts`: * Configure Anthropic client with a 4‑minute timeout and 3 retries * Wrap request logic in try/catch, log start and success, and surface clear timeout errors - Simplify `start.sh`: * Use `set -o allexport` and `source` to load environment variables instead of `export $(…)` pattern
…support to portable deployment - Add `.gitignore` rule for `deployment/portable/gcp-credentials.json` to keep GCP secrets out of the repo - Update `quick-export.sh` to set `DOCKER_UID`/`DOCKER_GID` for proper volume ownership - Include `docker-compose.infrastructure.yml` when building the main image - Copy `docker-compose.infrastructure-cpu.yml` into the export bundle to enable CPU‑only Vespa builds - These changes enable secure handling of GCP credentials and support exporting a CPU‑only Vespa build for environments without GPU support
…ectory - Adds `use-existing-data.sh` script in `deployment/portable/` - Updates compose files and `deploy.sh` to mount all data volumes to `../xyne-data/` instead of creating a new `./data/` directory - Backs up original data directories before switching - Prints a quick verification message to confirm the new mounts are in place
- Verify that `error` is an instance of `Error` before accessing `error.message` - Prevents runtime crashes when non-Error values are thrown - Improves type safety and reliability of the provider logic
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.
Actionable comments posted: 26
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
server/ai/provider/vertex_ai.ts (1)
243-257
: ReplacegoogleSearch
withgoogleSearchRetrieval
for Gemini 1.5
Gemini 1.5 in the Node SDK uses the legacygoogle_search_retrieval
tool, exposed asgoogleSearchRetrieval
. Update the snippet accordingly:- if (params.webSearch) { - tools.push({ googleSearch: {} }) - } + if (params.webSearch) { + tools.push({ googleSearchRetrieval: {} }) + }If you later support newer Gemini versions, you can conditionally revert to
googleSearch
.
🧹 Nitpick comments (67)
.gitignore (2)
212-212
: Anchor the portable export ignore to repo root for precisionPrepend a leading slash to avoid accidental matches in subfolders named "deployment" elsewhere.
-deployment/xyne-portable-* +/deployment/xyne-portable-*
215-215
: Keep app-assets directory present but emptyIgnoring the directory may cause missing-folder issues at runtime/build. Re-include a placeholder so the folder exists in fresh clones; or ensure your setup/start scripts create it.
-data/app-assets/ +/data/app-assets/* +!/data/app-assets/.gitkeepIf you prefer script-based creation, confirm
setup-deployment.sh
orstart.sh
mkdirs/data/app-assets
before use.server/vespa/deploy.sh (1)
56-61
: Fail fast if VESPA_HOST is unset and quote URL.Prevents silent empty host usage and odd CLI parsing; keeps behavior explicit.
-vespa deploy --wait 960 --target http://${VESPA_HOST}:19071 +vespa deploy --wait 960 --target "http://${VESPA_HOST:?set VESPA_HOST}:19071" @@ -vespa status --wait 75 --target http://${VESPA_HOST}:19071 +vespa status --wait 75 --target "http://${VESPA_HOST:?set VESPA_HOST}:19071"server/vespa/deploy-pod.sh (1)
32-34
: Guard VESPA_URL and add deploy wait for parity.Avoids running against an empty target and waits for activation like deploy.sh.
-vespa deploy --target $VESPA_URL +vespa deploy --wait 960 --target "${VESPA_URL:?set VESPA_URL}" @@ -vespa status --wait 55 --target $VESPA_URL +vespa status --wait 55 --target "${VESPA_URL:?set VESPA_URL}"Note: You also call
vespa config set target $VESPA_URL
above; passing--target
as well is redundant (fine to keep, or drop one).deployment/portable/Dockerfile-vespa-gpu (1)
1-1
: Pin the base image for reproducible builds.Unpinned images can break unexpectedly.
-FROM vespaengine/vespa +# Pin by digest or at least a major tag +# Example (replace with the actual digest you build/test against): +FROM vespaengine/vespa@sha256:<pin-digest-here>deployment/portable/docker-compose.yml (1)
6-6
: Add a trailing newline (YAMLlint).Fixes “no new line at end of file.”
-# Using simple bind mounts like dev setup - no named volumes needed +# Using simple bind mounts like dev setup - no named volumes needed +deployment/portable/grafana/provisioning/datasources/loki-datasource.yml (2)
1-1
: Fix typo in comment (“annd” → “and”).-# API version annd kind of the provisioning resource +# API version and kind of the provisioning resource
6-14
: Stabilize provisioning with a fixed UID and default flag.Prevents duplicate datasources across restarts and makes Loki default.
datasources: - name: Loki # Name of the data source in Grafana type: loki # Type of the data source + uid: loki access: proxy # Access mode: proxy (Grafana backend handles requests) or direct (browser handles requests) url: http://loki:3100 # URL of the Loki instance. 'loki' is the service name in Docker Compose. jsonData: # Optional: Add any Loki-specific jsonData fields if needed # For example, to set a default query or derived fields maxLines: 1000 - # isDefault: true # Uncomment if you want this to be the default Loki data source + isDefault: true # Set Loki as the default data source + editable: falsedeployment/portable/grafana/provisioning/datasources/postgres-datasource.yml (1)
12-13
: Avoid plaintext over the network; prefer SSL in non-local deployments.sslmode: disable is fine on an internal Docker network; for remote DBs, switch to require/verify-full and mount CA if applicable.
server/ai/provider/vertex_ai.ts (3)
131-157
: Harden error handling and keep stack/cause.
- Match timeouts by code/type if available, not substring 'timeout'.
- Preserve original stack via cause.
- } catch (error) { - Logger.error(`VertexAI Anthropic request failed:`, error) - if (error instanceof Error && error.message?.includes('timeout')) { - throw new Error(`VertexAI request timed out after 4 minutes`) - } - throw error - } + } catch (error: any) { + Logger.error(`VertexAI Anthropic request failed:`, error) + const msg = (error?.message || "").toLowerCase() + const isTimeout = msg.includes("timeout") || error?.name === "AbortError" + if (isTimeout) { + throw new Error(`VertexAI request timed out after 4 minutes`, { cause: error }) + } + throw (error instanceof Error ? error : new Error(String(error))) + }
250-271
: Use resolved model params consistently.You compute modelId via getModelParams but pass params.modelId here. Use modelId for consistency with defaults/aliases.
- const model = client.getGenerativeModel({ - model: params.modelId, + const model = client.getGenerativeModel({ + model: modelId,
486-489
: Fix stray quote and spacing in injected user text.There’s an extra " and a missing space in “image(s)as”. Minor polish to avoid odd prompts.
- text: `You may receive image(s)as part of the conversation. If images are attached, treat them as essential context for the user's question.\n\n" - ${userText}`, + text: `You may receive image(s) as part of the conversation. If images are attached, treat them as essential context for the user's question.\n\n${userText}`,deployment/portable/loki-config.yaml (2)
1-7
: Reduce log verbosity for routine use.debug is noisy; consider info for everyday portable runs, with an override via env if needed.
server: http_listen_port: 3100 grpc_listen_port: 9096 - log_level: debug + log_level: info
62-63
: Add newline at EOF to satisfy linters.Minor YAMLlint fix.
#analytics: # reporting_enabled: false +
.dockerignore (2)
35-43
: Include more common caches/temp dirs.Optional: exclude Python/Node caches to shrink context further.
**/tmp/ **/temp/ +.cache/ +**/.cache/ +**/.vite/ +**/.pytest_cache/ +**/.ruff_cache/
45-53
: Ignore common virtual envs.If any tooling uses Python, exclude virtualenvs from context.
# Editor files .vscode/ .idea/ *.swp *.swo +venv/ +.venv/ +**/.venv/deployment/portable/promtail-config.yaml (2)
29-69
: Trim trailing spaces and keep-only rule looks fine.Clean up YAML trailing spaces flagged by linters; logic for service detection and filtering looks solid.
- - source_labels: ['__meta_docker_container_name'] + - source_labels: ['__meta_docker_container_name'] regex: '/?(.*)' target_label: 'container_name' - + # Use container name as service if compose service label is missing - - source_labels: ['__meta_docker_container_name'] + - source_labels: ['__meta_docker_container_name'] regex: '/?(.*)' target_label: 'service' - + # Override with compose service name if available - - source_labels: ['__meta_docker_container_label_com_docker_compose_service'] + - source_labels: ['__meta_docker_container_label_com_docker_compose_service'] regex: '(.+)' target_label: 'service' - + # Add log stream (stdout/stderr) - - source_labels: ['__meta_docker_container_log_stream'] + - source_labels: ['__meta_docker_container_log_stream'] target_label: 'stream' - + # Add container ID for debugging - - source_labels: ['__meta_docker_container_id'] + - source_labels: ['__meta_docker_container_id'] regex: '(.{12}).*' target_label: 'container_id' - + # Add image name - - source_labels: ['__meta_docker_container_label_com_docker_compose_image'] + - source_labels: ['__meta_docker_container_label_com_docker_compose_image'] target_label: 'image' - + # Fallback to docker image if compose image not available - - source_labels: ['__meta_docker_container_image'] + - source_labels: ['__meta_docker_container_image'] regex: '([^:]+):?.*' target_label: 'image' - + # Add project name if available - - source_labels: ['__meta_docker_container_label_com_docker_compose_project'] + - source_labels: ['__meta_docker_container_label_com_docker_compose_project'] target_label: 'project' - + # Only collect logs from containers with our project prefix or xyne network - source_labels: ['__meta_docker_container_name', '__meta_docker_network_mode'] regex: '/(xyne-.*|.*xyne.*|loki|promtail|grafana|vespa|postgres).*;.*' action: keep
11-21
: Consider adding a pipeline to parse JSON logs (if app logs are JSON).If /var/log/app/*.log are JSON, add a json stage to extract level/message/service.
- job_name: app-logs static_configs: - targets: - localhost labels: job: app-logs service: xyne-app __path__: /var/log/app/*.log + pipeline_stages: + - json: + expressions: + level: level + msg: message + ts: time + - labels: + level: + service:deployment/portable/quick-export.sh (5)
12-16
: Remove unused color or use it.
RED
is defined but unused. Clean it or use in error trap.-GREEN='\033[0;32m' -BLUE='\033[0;34m' -YELLOW='\033[1;33m' -RED='\033[0;31m' -NC='\033[0m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +YELLOW='\033[1;33m' +NC='\033[0m'
22-51
: Switch arg parsing to while/case; stop calling shift inside for-loop.
shift
insidefor arg in "$@"
is a smell and misleading. Use conventional loop; reject unknown flags.-for arg in "$@"; do - case $arg in - --no-export) - NO_EXPORT=true - shift - ;; - --force-build) - FORCE_BUILD=true - shift - ;; - cleanup) - echo -e "${YELLOW}🧹 Cleaning up old export directories...${NC}" - rm -rf xyne-portable-* - echo -e "${GREEN}✅ Cleanup completed!${NC}" - exit 0 - ;; - --help|-h) - echo "Usage: $0 [OPTIONS]" - echo "Options:" - echo " --no-export Skip creating tar file (for same-machine deployment)" - echo " --force-build Force rebuild even if remote image is newer" - echo " cleanup Remove old export directories" - echo " --help, -h Show this help message" - exit 0 - ;; - *) - # Unknown option - ;; - esac -done +while [[ $# -gt 0 ]]; do + case "$1" in + --no-export) NO_EXPORT=true; shift ;; + --force-build) FORCE_BUILD=true; shift ;; + cleanup) + echo -e "${YELLOW}🧹 Cleaning up old export directories...${NC}" + rm -rf -- xyne-portable-* + echo -e "${GREEN}✅ Cleanup completed!${NC}" + exit 0 + ;; + --help|-h) + echo "Usage: $0 [--no-export] [--force-build] [cleanup] [--help|-h]" + exit 0 + ;; + *) echo -e "${YELLOW}Unknown option: $1${NC}"; exit 2 ;; + esac +done
57-58
: Address SC2155: assign then export to avoid masking.Minor ShellCheck fix.
-export DOCKER_UID=$(id -u) -export DOCKER_GID=$(id -g) +DOCKER_UID="$(id -u)"; export DOCKER_UID +DOCKER_GID="$(id -g)"; export DOCKER_GID
73-78
: Robust image existence check.
docker images | grep xyne-vespa-gpu
can false-match. Inspect the image explicitly.-if [ "$FORCE_BUILD" = "true" ] || ! docker images | grep -q "xyne-vespa-gpu"; then +if [ "$FORCE_BUILD" = "true" ] || ! docker image inspect xyne-vespa-gpu:latest >/dev/null 2>&1; then
81-91
: Stream-compress saves to cut disk I/O.Saves are followed by gzip; stream instead.
- docker save -o "$EXPORT_DIR/xyne-app.tar" xyne - gzip "$EXPORT_DIR/xyne-app.tar" + docker save xyne | gzip -c > "$EXPORT_DIR/xyne-app.tar.gz" @@ - docker save -o "$EXPORT_DIR/xyne-vespa-gpu.tar" xyne-vespa-gpu - gzip "$EXPORT_DIR/xyne-vespa-gpu.tar" + docker save xyne-vespa-gpu | gzip -c > "$EXPORT_DIR/xyne-vespa-gpu.tar.gz"deployment/portable/grafana/provisioning/dashboards/default-dashboards-provider.yml (2)
11-11
: Fix misleading inline comment foreditable
.Comment says “If true …” while value is
false
. Align wording to avoid confusion.- editable: false # If true, dashboards can be edited in the UI. Changes won't save back to JSON by default. + editable: false # When true, dashboards can be edited in the UI (changes won't write back to JSON).
16-16
: Add trailing newline.Satisfy linters and POSIX text-file convention.
- # reflected in Grafana's UI. + # reflected in Grafana's UI. +deployment/portable/prometheus-selfhosted.yml (3)
7-7
: Trim trailing whitespace.YAML lint failure on Line 7.
- +
12-12
: Clarify the inline instruction and avoid spacing glitch.Minor doc tweak.
- - targets: ['xyne-app:3001'] #replace with your application's service name e.g. 'xyne-app:3000' or the host-name:port where your server is hosted + - targets: ['xyne-app:3001'] # replace with your app's service name (e.g., 'xyne-app:3000') or host:port
1-5
: Consider a global scrape interval.Set a top-level
global.scrape_interval
and override per job only when needed.+global: + scrape_interval: 10s + scrape_configs: - job_name: 'vespa-data-ingest' - scrape_interval: 10s + # uses global 10sdeployment/portable/grafana/provisioning/datasources/prometheus-datasource.yml (1)
5-10
: Add a stable UID for the data source to keep dashboard bindings consistent.Prevents re-seeding from creating duplicate unnamed data sources.
- name: PrometheusLocal # Or any name you prefer + uid: prometheus type: prometheus access: proxy # Server access mode is generally recommended url: http://xyne-prometheus:9090 # Use the service name from docker-compose isDefault: true editable: false # Set to true if you want to allow UI edits
deployment/portable/.env.default (2)
4-4
: Drop unnecessary quotes to avoid surprising parsing.Quoted values are read literally (including the quotes) by some dotenv loaders.
-EMBEDDING_MODEL="bge-small-en-v1.5" +EMBEDDING_MODEL=bge-small-en-v1.5 -REASONING="true" +REASONING=trueAlso applies to: 7-7
17-17
: Provide a sensible default for NODE_ENV.Portable deployment should default to production unless overridden.
-NODE_ENV= +NODE_ENV=productiondeployment/portable/grafana/provisioning/dashboards/xyne-pm2-logs.json (2)
65-66
: Rename panel.- "title": "New panel", + "title": "PM2 logs",
41-49
: Improve log readability (time + wrapping).- "showTime": false, - "wrapLogMessage": false + "showTime": true, + "wrapLogMessage": truedeployment/portable/grafana/provisioning/dashboards/vespa-detailed-monitoring.json (5)
568-621
: Set correct units for latency panels.Axis says ms but unit is "short". Use "ms" for consistency and auto-formatting.
Example (95p panel):
- "unit": "short" + "unit": "ms"Apply similarly to 99p and mean panels.
Also applies to: 639-673, 675-785, 787-898
183-219
: Use Grafana units instead of manual scaling where possible.For MB panels, prefer unit "megabytes" and keep bytes in query, or keep division and set unit "megabytes" for consistent formatting.
- "unit": "short" + "unit": "megabytes"
1270-1303
: Percent panels: set percent unit.- "unit": "short" + "unit": "percent (0-100)"Also applies to: 1381-1415
279-296
: Remove environment-specific byName overrides.Matchers include exact instance/vespaVersion/job labels; they’ll break on version/host changes. Prefer generic series matchers or color by query refId.
Also applies to: 393-410, 621-638, 733-750, 1154-1171
1418-1419
: Enable auto-refresh.refresh=false disables live dashboards. Suggest a sane default (e.g., 10s/30s).
deployment/portable/README.md (3)
25-36
: Add language to fenced block.-``` +```text portable/ ├── docker-compose.yml # Base configuration ...--- `76-82`: **Avoid bare URLs for lint compliance.** ```diff -- **Xyne Application**: http://localhost:3000 -- **Grafana Dashboard**: http://localhost:3002 -- **Prometheus Metrics**: http://localhost:9090 -- **Loki Logs**: http://localhost:3100 +- **Xyne Application**: [http://localhost:3000](http://localhost:3000) +- **Grafana Dashboard**: [http://localhost:3002](http://localhost:3002) +- **Prometheus Metrics**: [http://localhost:9090](http://localhost:9090) +- **Loki Logs**: [http://localhost:3100](http://localhost:3100)
103-111
: Add a step to generate required secrets.Example snippet to insert after step 2:
# Generate secrets (example) openssl rand -hex 32 | sed 's/^/ENCRYPTION_KEY=/' >> .env openssl rand -hex 32 | sed 's/^/JWT_SECRET=/' >> .env openssl rand -hex 32 | sed 's/^/USER_SECRET=/' >> .envDockerfile (3)
8-8
: Support both lockfile names consistently.-COPY frontend/package.json frontend/bun.lockb /usr/src/app/frontend/ +COPY frontend/package.json frontend/bun.lock* /usr/src/app/frontend/
38-59
: Parameterize Vespa CLI version and verify integrity.-# Install required tools, canvas dependencies, and vespa CLI +# Install required tools, canvas dependencies, and vespa CLI +ARG VESPA_CLI_VERSION=8.453.24 ... - && wget https://github.com/vespa-engine/vespa/releases/download/v8.453.24/vespa-cli_8.453.24_linux_amd64.tar.gz \ - && tar -xzf vespa-cli_8.453.24_linux_amd64.tar.gz \ - && mv vespa-cli_8.453.24_linux_amd64/bin/vespa /usr/local/bin/ \ - && rm -rf vespa-cli_8.453.24_linux_amd64 vespa-cli_8.453.24_linux_amd64.tar.gz \ + && wget -O vespa-cli.tar.gz https://github.com/vespa-engine/vespa/releases/download/v${VESPA_CLI_VERSION}/vespa-cli_${VESPA_CLI_VERSION}_linux_amd64.tar.gz \ + && tar -xzf vespa-cli.tar.gz \ + && mv vespa-cli_${VESPA_CLI_VERSION}_linux_amd64/bin/vespa /usr/local/bin/ \ + && rm -rf vespa-cli_${VESPA_CLI_VERSION}_linux_amd64 vespa-cli.tar.gz \Optionally add checksum verification for the tarball.
40-59
: Slim the image (multi-stage).-dev packages inflate the final image. Consider building native deps in a builder stage and copying only runtime libs.
deployment/portable/use-existing-data.sh (3)
11-18
: Harden script options (avoid silent failures).Prefer strict mode and a trap for better safety in prod.
-set -e +set -Eeuo pipefail +trap 'echo -e "${RED}❌ Failed at line ${BASH_LINENO[0]}${NC}"' ERR
53-61
: Substitution coverage may miss quoted or non-leading volume paths.Current sed only matches lines starting with “- ./data/”. Compose files may include quotes or additional indentation. Broaden patterns to catch
"./data/..."
and leading spaces.- sed -i.tmp 's|^\( *- \)\./data/|\1../xyne-data/|g' "$file" + # match: - ./data/... OR - "./data/..." with any indent + sed -i.tmp -E 's|^([[:space:]]*-\s+)"?\.\/data/|\1../xyne-data/|g' "$file"
91-96
: Verification only shows first 5 matches; can hide misses.Consider grepping all matches per file to ensure every intended substitution occurred.
-grep -n "xyne-data" docker-compose*.yml deploy.sh | head -5 || true +grep -n "xyne-data" docker-compose*.yml deploy.sh || truestart.sh (1)
24-27
: Add timeouts to Vespa healthchecks to avoid hanging curls.Small hardening: fail fast per attempt.
-until curl -f http://vespa:19071/state/v1/health 2>/dev/null; do +until curl -fsS --connect-timeout 3 --max-time 5 http://vespa:19071/state/v1/health >/dev/null; dodeployment/portable/docker-compose.app.yml (2)
31-35
: Useservice_healthy
for Vespa since a healthcheck exists.Stronger readiness gating.
- vespa: - condition: service_started + vespa: + condition: service_healthy
43-47
: Permission alignment between init and app user.Init chowns to 1000:1000 but the app may run as other IDs via DOCKER_UID/GID. Consider chowning to those IDs to avoid permission issues.
deployment/portable/grafana/provisioning/dashboards/xyne_pm2_metrics.json (3)
24-84
: Minor wording: “Total Running application” → “Total running applications”.Purely cosmetic.
- "title": "Total Running application", + "title": "Total running applications",
25-28
: Datasource UID coupling.The dashboard pins a specific datasource UID. Ensure your Prometheus provisioning sets uid=P442C0F3243930FD5; otherwise switch to a named datasource to reduce coupling.
821-833
: Legend label forpm2_free_memory
may not includeapp
.If this metric lacks an
app
label, legends will be blank. Consider removing{{app}}
here.deployment/portable/docker-compose.infrastructure-cpu.yml (4)
43-45
: Remove trailing space in Grafana volume and add EOF newline.Lint issues: trailing space and missing newline at end of file.
- - ./data/grafana-storage:/var/lib/grafana + - ./data/grafana-storage:/var/lib/grafana(Ensure the file ends with a newline.)
38-46
: Clarify Grafana DB settings.Providing POSTGRES_* alone doesn’t switch Grafana to Postgres. Either remove them or set GF_DATABASE_* env vars.
Example:
environment: GF_DATABASE_TYPE: postgres GF_DATABASE_HOST: xyne-db:5432 GF_DATABASE_USER: xyne GF_DATABASE_PASSWORD: xyne GF_DATABASE_NAME: grafana
54-63
: Pin image versions for reproducibility.
latest
tags can break deployments unexpectedly. Pin to known-good versions.- image: vespaengine/vespa:latest + image: vespaengine/vespa:8.326.25 # example(Apply similarly to Prometheus and Grafana.)
158-176
: Promtail runs as root; prefer non-root with docker group if possible.Minimize privileges by dropping root if access permits.
docs/deployment/advanced/portable-deployment.mdx (3)
34-41
: Standardize on “docker compose” (v2) CLI.Docs require Compose 2.0+ but show
docker-compose --version
. Recommend usingdocker compose
consistently to avoid v1/v2 mismatches.Apply:
- Verify with: `docker-compose --version` + Verify with: `docker compose version`
301-305
: Validate HOST variable format.If the app expects HOST as a hostname rather than a URL,
HOST=http://localhost
may cause issues. Confirm and, if needed, split intoHOST=localhost
andPUBLIC_URL=http://localhost:3000
.
471-485
: GPU validation tip: update CUDA base image tag (optional).
nvidia/cuda:11.0-base
is dated. Considernvidia/cuda:12.x-base
for broader driver compatibility in 2025.deployment/portable/docker-compose.infrastructure.yml (4)
27-35
: YAML lint: indentation for ports and extra_hosts.Fix indentation to satisfy linters and avoid brittle parsing.
ports: - - "9090:9090" + - "9090:9090" @@ extra_hosts: - - "host.docker.internal:host-gateway" + - "host.docker.internal:host-gateway"
43-43
: Trailing space.Remove trailing space after the Grafana volume path.
- - ./data/grafana-storage:/var/lib/grafana + - ./data/grafana-storage:/var/lib/grafana
187-187
: Missing newline at EOF.Add a newline to satisfy tooling.
xyne: external: true +
96-120
: Postgres healthcheck: consider explicit--timeout
and--host
.Minor robustness:
pg_isready
can hang if DNS is slow. Add host and timeout to fail fast.- test: ["CMD-SHELL", "pg_isready -U xyne -d xyne"] + test: ["CMD-SHELL", "pg_isready -h localhost -U xyne -d xyne -t 5"]deployment/portable/deploy.sh (3)
295-313
: Fragile PS check for app status.Grepping for
xyne-app.*Up
depends on container naming. Scope to the service and check for “Up”.- if ! docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml ps | grep -q "xyne-app.*Up"; then + if ! docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml ps app | grep -q "Up"; thenRepeat the same change in
db_migrate
anddb_studio
.
120-168
: Make Compose CLI selectable (docker compose vs docker-compose).Some environments only have
docker compose
. Add a small wrapper and use it everywhere.show_help() { @@ } +compose() { + if command -v docker-compose >/dev/null 2>&1; then + docker-compose "$@" + else + docker compose "$@" + fi +}Then replace direct
docker-compose ...
calls withcompose ...
.
283-288
: Cleanup may remove unrelated named volumes.
docker volume prune -f
removes all unused volumes on the host. Consider scoping cleanup to this project or warn users.- docker volume prune -f + # docker volume prune -f # Uncomment if you intend to prune globally
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (29)
.dockerignore
(1 hunks).gitignore
(1 hunks)Dockerfile
(1 hunks)deployment/portable/.env.default
(1 hunks)deployment/portable/Dockerfile-vespa-gpu
(1 hunks)deployment/portable/README.md
(1 hunks)deployment/portable/deploy.sh
(1 hunks)deployment/portable/docker-compose.app.yml
(1 hunks)deployment/portable/docker-compose.infrastructure-cpu.yml
(1 hunks)deployment/portable/docker-compose.infrastructure.yml
(1 hunks)deployment/portable/docker-compose.yml
(1 hunks)deployment/portable/grafana/provisioning/dashboards/default-dashboards-provider.yml
(1 hunks)deployment/portable/grafana/provisioning/dashboards/vespa-detailed-monitoring.json
(1 hunks)deployment/portable/grafana/provisioning/dashboards/xyne-pm2-logs.json
(1 hunks)deployment/portable/grafana/provisioning/dashboards/xyne_pm2_metrics.json
(1 hunks)deployment/portable/grafana/provisioning/datasources/loki-datasource.yml
(1 hunks)deployment/portable/grafana/provisioning/datasources/postgres-datasource.yml
(1 hunks)deployment/portable/grafana/provisioning/datasources/prometheus-datasource.yml
(1 hunks)deployment/portable/loki-config.yaml
(1 hunks)deployment/portable/prometheus-selfhosted.yml
(1 hunks)deployment/portable/promtail-config.yaml
(1 hunks)deployment/portable/quick-export.sh
(1 hunks)deployment/portable/use-existing-data.sh
(1 hunks)docs/deployment/advanced/portable-deployment.mdx
(1 hunks)docs/mint.json
(1 hunks)server/ai/provider/vertex_ai.ts
(2 hunks)server/vespa/deploy-pod.sh
(1 hunks)server/vespa/deploy.sh
(1 hunks)start.sh
(1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/deployment/advanced/portable-deployment.mdx
[grammar] ~17-~17: There might be a mistake here.
Context: ...rements ### Minimum System Requirements - OS: Linux (Ubuntu 20.04+ recommended),...
(QB_NEW_EN)
[grammar] ~18-~18: There might be a mistake here.
Context: ...ecommended), macOS, or Windows with WSL2 - RAM: 8GB minimum, 16GB+ recommended - ...
(QB_NEW_EN)
[grammar] ~19-~19: There might be a mistake here.
Context: ... RAM: 8GB minimum, 16GB+ recommended - Storage: 50GB+ available disk space - ...
(QB_NEW_EN)
[grammar] ~20-~20: There might be a mistake here.
Context: ... Storage: 50GB+ available disk space - CPU: 4+ cores recommended ### Require...
(QB_NEW_EN)
[grammar] ~43-~43: There might be a mistake here.
Context: ... ### GPU Support (Optional) For optimal search performance with GPU-...
(QB_NEW_EN)
[grammar] ~156-~156: There might be a mistake here.
Context: ...ent orchestration ``` Benefits: - Fast app updates: Update application w...
(QB_NEW_EN)
[grammar] ~301-~301: There might be a mistake here.
Context: ...TABASE_NAME=xyne # Application Settings NODE_ENV=production HOST=http://localhos...
(QB_NEW_EN)
[grammar] ~302-~302: There might be a mistake here.
Context: ...Application Settings NODE_ENV=production HOST=http://localhost PORT=3000 # Searc...
(QB_NEW_EN)
[grammar] ~303-~303: There might be a mistake here.
Context: ...ODE_ENV=production HOST=http://localhost PORT=3000 # Search Engine VESPA_HOST=ve...
(QB_NEW_EN)
[grammar] ~306-~306: There might be a mistake here.
Context: ...p://localhost PORT=3000 # Search Engine VESPA_HOST=vespa VESPA_PORT=8080 EMBEDDI...
(QB_NEW_EN)
[grammar] ~307-~307: There might be a mistake here.
Context: ...T=3000 # Search Engine VESPA_HOST=vespa VESPA_PORT=8080 EMBEDDING_MODEL=bge-smal...
(QB_NEW_EN)
[grammar] ~308-~308: There might be a mistake here.
Context: ... Engine VESPA_HOST=vespa VESPA_PORT=8080 EMBEDDING_MODEL=bge-small-en-v1.5 ``` `...
(QB_NEW_EN)
[grammar] ~347-~347: There might be a mistake here.
Context: ...Settings (adjust based on available RAM) VESPA_CONFIGSERVER_JVMARGS="-Xms1g -Xmx1...
(QB_NEW_EN)
[grammar] ~348-~348: There might be a mistake here.
Context: ...ER_JVMARGS="-Xms1g -Xmx16g -XX:+UseG1GC" VESPA_CONFIGPROXY_JVMARGS="-Xms512m -Xmx...
(QB_NEW_EN)
[grammar] ~388-~388: There might be a mistake here.
Context: ... Metrics storage ``` Backup Strategy: - Regular backup of postgres-data/
for d...
(QB_NEW_EN)
[grammar] ~389-~389: There might be a mistake here.
Context: ... backup of postgres-data/
for database - Backup app-migrations/
for schema hist...
(QB_NEW_EN)
[grammar] ~390-~390: There might be a mistake here.
Context: ...kup app-migrations/
for schema history - Backup vespa-data/
for search indices ...
(QB_NEW_EN)
[grammar] ~391-~391: There might be a mistake here.
Context: ...ta/for search indices (can be rebuilt) - Include
app-uploads/` for user content ...
(QB_NEW_EN)
[grammar] ~394-~394: There might be a mistake here.
Context: ...r user content Migration Persistence: - Drizzle migrations are stored in `app-mi...
(QB_NEW_EN)
[grammar] ~447-~447: There might be a mistake here.
Context: ... monitoring ports # Grafana: "3002:3000" # Prometheus: "9090:9090" # Loki: "3100:3...
(QB_NEW_EN)
[grammar] ~448-~448: There might be a mistake here.
Context: ...a: "3002:3000" # Prometheus: "9090:9090" # Loki: "3100:3100" ``` ## T...
(QB_NEW_EN)
deployment/portable/README.md
[grammar] ~16-~16: There might be a mistake here.
Context: ...One-click deployment** - Complete setup with single command - ⚡ Fast app updates...
(QB_NEW_EN)
[grammar] ~16-~16: There might be a mistake here.
Context: ...t** - Complete setup with single command - ⚡ Fast app updates - Update applicatio...
(QB_NEW_EN)
[grammar] ~17-~17: There might be a mistake here.
Context: ... without touching database/search (~30s vs 3+ min) - 🔧 Modular architecture -...
(QB_NEW_EN)
[grammar] ~17-~17: There might be a mistake here.
Context: ...ouching database/search (~30s vs 3+ min) - 🔧 Modular architecture - Separate inf...
(QB_NEW_EN)
[grammar] ~18-~18: There might be a mistake here.
Context: ... infrastructure and application concerns - 📊 Built-in monitoring - Grafana, Prom...
(QB_NEW_EN)
[grammar] ~19-~19: There might be a mistake here.
Context: ...lt-in monitoring** - Grafana, Prometheus, Loki included - 🔄 Export/Import - ...
(QB_NEW_EN)
[grammar] ~19-~19: There might be a mistake here.
Context: ...g** - Grafana, Prometheus, Loki included - 🔄 Export/Import - Easy transfer betwe...
(QB_NEW_EN)
[grammar] ~20-~20: There might be a mistake here.
Context: ...mport** - Easy transfer between machines - 🎯 Auto GPU/CPU detection - Automatica...
(QB_NEW_EN)
[grammar] ~21-~21: There might be a mistake here.
Context: ...y uses GPU acceleration when available, falls back to CPU-only mode ## Directory Str...
(QB_NEW_EN)
[grammar] ~21-~21: There might be a mistake here.
Context: ...n available, falls back to CPU-only mode ## Directory Structure ``` portable/ ├── d...
(QB_NEW_EN)
[grammar] ~78-~78: There might be a mistake here.
Context: ...yne Application**: http://localhost:3000 - Grafana Dashboard: http://localhost:30...
(QB_NEW_EN)
[grammar] ~79-~79: There might be a mistake here.
Context: ...afana Dashboard**: http://localhost:3002 - Prometheus Metrics: http://localhost:9...
(QB_NEW_EN)
[grammar] ~80-~80: There might be a mistake here.
Context: ...metheus Metrics**: http://localhost:9090 - Loki Logs: http://localhost:3100 ## R...
(QB_NEW_EN)
[grammar] ~85-~85: There might be a mistake here.
Context: ...ost:3100 ## Requirements ### Essential - Docker Engine 20.10+ - Docker Compose 2....
(QB_NEW_EN)
[grammar] ~86-~86: There might be a mistake here.
Context: ...ts ### Essential - Docker Engine 20.10+ - Docker Compose 2.0+ - 8GB+ RAM (16GB+ re...
(QB_NEW_EN)
[grammar] ~87-~87: There might be a mistake here.
Context: ...cker Engine 20.10+ - Docker Compose 2.0+ - 8GB+ RAM (16GB+ recommended) - 50GB+ d...
(QB_NEW_EN)
[grammar] ~88-~88: There might be a mistake here.
Context: ...pose 2.0+ - 8GB+ RAM (16GB+ recommended) - 50GB+ disk space ### Optional (for GPU ...
(QB_NEW_EN)
[grammar] ~91-~91: There might be a mistake here.
Context: ...ace ### Optional (for GPU acceleration) - NVIDIA GPU with CUDA support - NVIDIA Co...
(QB_NEW_EN)
[grammar] ~92-~92: There might be a mistake here.
Context: ...leration) - NVIDIA GPU with CUDA support - NVIDIA Container Toolkit - Note: Sys...
(QB_NEW_EN)
[grammar] ~93-~93: There might be a mistake here.
Context: ... CUDA support - NVIDIA Container Toolkit - Note: System automatically detects GPU...
(QB_NEW_EN)
[grammar] ~115-~115: There might be a mistake here.
Context: ...tation**: See Portable Deployment Guide ## Advantages Over Simple Docker Compose |...
(QB_NEW_EN)
[grammar] ~119-~119: There might be a mistake here.
Context: ...| Simple Compose | Portable Deployment | |---------|---------------|-------------...
(QB_NEW_EN)
[grammar] ~120-~120: There might be a mistake here.
Context: ...---|---------------|-------------------| | App Updates | Full restart (~3+ min) |...
(QB_NEW_EN)
[grammar] ~121-~121: There might be a mistake here.
Context: ...rt (~3+ min) | App-only restart (~30s) | | Infrastructure Management | Manual | A...
(QB_NEW_EN)
[grammar] ~122-~122: There might be a mistake here.
Context: ... Manual | Automated with health checks | | Monitoring | None | Grafana + Promethe...
(QB_NEW_EN)
[grammar] ~123-~123: There might be a mistake here.
Context: ...g | None | Grafana + Prometheus + Loki | | Export/Import | Manual | Built-in scri...
(QB_NEW_EN)
[grammar] ~124-~124: There might be a mistake here.
Context: ...ort/Import | Manual | Built-in scripts | | Production Ready | Basic | Advanced wi...
(QB_NEW_EN)
[grammar] ~125-~125: There might be a mistake here.
Context: ...Ready | Basic | Advanced with security | | Permission Management | Manual | Autom...
(QB_NEW_EN)
🪛 YAMLlint (1.37.1)
deployment/portable/docker-compose.infrastructure-cpu.yml
[warning] 27-27: wrong indentation: expected 6 but found 4
(indentation)
[warning] 35-35: wrong indentation: expected 6 but found 4
(indentation)
[error] 43-43: trailing spaces
(trailing-spaces)
[error] 180-180: no new line character at the end of file
(new-line-at-end-of-file)
deployment/portable/grafana/provisioning/dashboards/default-dashboards-provider.yml
[error] 16-16: no new line character at the end of file
(new-line-at-end-of-file)
deployment/portable/loki-config.yaml
[error] 63-63: no new line character at the end of file
(new-line-at-end-of-file)
deployment/portable/promtail-config.yaml
[error] 32-32: trailing spaces
(trailing-spaces)
[error] 37-37: trailing spaces
(trailing-spaces)
[error] 42-42: trailing spaces
(trailing-spaces)
[error] 46-46: trailing spaces
(trailing-spaces)
[error] 51-51: trailing spaces
(trailing-spaces)
[error] 55-55: trailing spaces
(trailing-spaces)
[error] 60-60: trailing spaces
(trailing-spaces)
[error] 64-64: trailing spaces
(trailing-spaces)
deployment/portable/prometheus-selfhosted.yml
[error] 7-7: trailing spaces
(trailing-spaces)
deployment/portable/docker-compose.yml
[error] 6-6: no new line character at the end of file
(new-line-at-end-of-file)
deployment/portable/docker-compose.infrastructure.yml
[warning] 27-27: wrong indentation: expected 6 but found 4
(indentation)
[warning] 35-35: wrong indentation: expected 6 but found 4
(indentation)
[error] 43-43: trailing spaces
(trailing-spaces)
[error] 187-187: no new line character at the end of file
(new-line-at-end-of-file)
🪛 markdownlint-cli2 (0.17.2)
deployment/portable/README.md
25-25: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
78-78: Bare URL used
(MD034, no-bare-urls)
79-79: Bare URL used
(MD034, no-bare-urls)
80-80: Bare URL used
(MD034, no-bare-urls)
81-81: Bare URL used
(MD034, no-bare-urls)
🪛 Shellcheck (0.10.0)
deployment/portable/quick-export.sh
[warning] 15-15: RED appears unused. Verify use (or export if used externally).
(SC2034)
[warning] 57-57: Declare and assign separately to avoid masking return values.
(SC2155)
[warning] 58-58: Declare and assign separately to avoid masking return values.
(SC2155)
🪛 dotenv-linter (3.3.0)
deployment/portable/.env.default
[warning] 3-3: [UnorderedKey] The HOST key should go before the VESPA_HOST key
(UnorderedKey)
[warning] 4-4: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 4-4: [UnorderedKey] The EMBEDDING_MODEL key should go before the HOST key
(UnorderedKey)
[warning] 5-5: [UnorderedKey] The DATABASE_URL key should go before the EMBEDDING_MODEL key
(UnorderedKey)
[warning] 6-6: [UnorderedKey] The POSTGRES_PASSWORD key should go before the VESPA_HOST key
(UnorderedKey)
[warning] 7-7: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 7-7: [UnorderedKey] The REASONING key should go before the VESPA_HOST key
(UnorderedKey)
[warning] 8-8: [UnorderedKey] The GOOGLE_REDIRECT_URI key should go before the HOST key
(UnorderedKey)
[warning] 9-9: [UnorderedKey] The GOOGLE_CLIENT_ID key should go before the GOOGLE_REDIRECT_URI key
(UnorderedKey)
[warning] 10-10: [UnorderedKey] The GOOGLE_CLIENT_SECRET key should go before the GOOGLE_REDIRECT_URI key
(UnorderedKey)
[warning] 11-11: [UnorderedKey] The ENCRYPTION_KEY key should go before the GOOGLE_CLIENT_ID key
(UnorderedKey)
[warning] 12-12: [UnorderedKey] The JWT_SECRET key should go before the POSTGRES_PASSWORD key
(UnorderedKey)
[warning] 13-13: [UnorderedKey] The SERVICE_ACCOUNT_ENCRYPTION_KEY key should go before the VESPA_HOST key
(UnorderedKey)
[warning] 14-14: [UnorderedKey] The AWS_ACCESS_KEY key should go before the DATABASE_HOST key
(UnorderedKey)
[warning] 15-15: [UnorderedKey] The AWS_SECRET_KEY key should go before the DATABASE_HOST key
(UnorderedKey)
[warning] 16-16: [UnorderedKey] The AWS_REGION key should go before the AWS_SECRET_KEY key
(UnorderedKey)
[warning] 17-17: [UnorderedKey] The NODE_ENV key should go before the POSTGRES_PASSWORD key
(UnorderedKey)
[warning] 18-18: [UnorderedKey] The USER_SECRET key should go before the VESPA_HOST key
(UnorderedKey)
🔇 Additional comments (12)
server/ai/provider/vertex_ai.ts (1)
85-90
: No changes needed—AnthropicVertex
acceptstimeout
andmaxRetries
in its constructor. The Vertex SDK client extends the main Anthropic client and forwards all base options, includingtimeout
andmaxRetries
(classic.yarnpkg.com, github.com)..dockerignore (1)
18-28
: Good call excluding large data; keep portable compose artifacts available.Patterns avoid shipping runtime data into images. LGTM.
deployment/portable/quick-export.sh (1)
69-76
: Verify Compose image names match expected save tags
Ensure theapp
andvespa
services in your Compose files explicitly setimage: xyne
andimage: xyne-vespa-gpu
; otherwisedocker save xyne xyne-vespa-gpu
will fail. Manually confirm indocker-compose.yml
,docker-compose.app.yml
, anddocker-compose.infrastructure.yml
that these names are defined for lines 69–76 and 85–90.docs/mint.json (1)
75-79
: LGTM: Adds “Advanced Deployment → Portable Deployment” entry.Structure conforms to Mintlify grouped navigation. No issues spotted.
deployment/portable/grafana/provisioning/datasources/prometheus-datasource.yml (1)
8-8
: No changes needed; Compose container_name ‘xyne-prometheus’ on port 9090 matches the Grafana datasource URL.deployment/portable/.env.default (1)
14-16
: Confirm AWS env var names.Most SDKs expect AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY; the current names may be ignored.
If needed:
-AWS_ACCESS_KEY= -AWS_SECRET_KEY= +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY=deployment/portable/grafana/provisioning/dashboards/xyne-pm2-logs.json (1)
60-60
: Verify label selector.Confirm promtail sets job="pm2"; if not, update the selector to match your scrape config.
deployment/portable/grafana/provisioning/dashboards/vespa-detailed-monitoring.json (1)
106-117
: CPU query likely invalid.expr "cpu" is unusual; ensure a valid PromQL (e.g., process or node CPU) and aggregation.
Example:
- Node: rate(node_cpu_seconds_total{mode!="idle"}[5m]) |> sum by (instance)
- Vespa: adjust to the exported metric you actually emit.
Dockerfile (1)
84-86
: Confirm exposed ports match runtime.start.sh must bind to 3000/3001 inside the container; compose mappings should align.
start.sh (1)
16-19
: Postgres wait command uses invalid Bun syntax (bun run -e
).Bun evaluates code with
bun -e
(notbun run -e
). Current loop will never succeed.-until bun run -e "import postgres from 'postgres'; const sql = postgres({host: process.env.DATABASE_HOST || 'xyne-db', port: 5432, database: 'xyne', username: 'xyne', password: 'xyne'}); await sql\`SELECT 1\`; await sql.end();" 2>/dev/null; do +until bun -e "import postgres from 'postgres'; const sql = postgres({host: process.env.DATABASE_HOST || 'xyne-db', port: Number(process.env.DATABASE_PORT || 5432), database: process.env.DATABASE_NAME || 'xyne', username: process.env.DATABASE_USER || 'xyne', password: process.env.DATABASE_PASSWORD || 'xyne'}); await sql\`SELECT 1\`; await sql.end();" 2>/dev/null; doLikely an incorrect or invalid review comment.
deployment/portable/docker-compose.app.yml (1)
26-28
: Ensure port mapping matchesstart.sh
The current mapping ("3000:80"
) doesn’t align with the app’s bound port.
- If
start.sh
uses the defaultPORT=3000
, update to:- - "3000:80" + - "3000:3000"- If you prefer binding inside to port 80, set
PORT=80
instart.sh
, keep- "3000:80"
, and adjust the healthcheck URL to target port 80.deployment/portable/docker-compose.infrastructure.yml (1)
60-75
: Incorrect GPU config suggestion:deploy.resources.reservations.devices
is supported by Docker Compose V2 for non-Swarmdocker compose up
; no changes needed.Likely an incorrect or invalid review comment.
- Ignore GCP credentials file in build context - Add Docker UID/GID variables and `${DATABASE_HOST}` placeholder to portable deployment defaults - Launch Drizzle Studio in a new container rather than execing into an existing one - Refactor startup script: `set -euo pipefail`, conditional tracing, load environment earlier - Remove duplicated env load block and pre‑service data‑restore step - Make migration commands non‑fatal (`|| true`) for robust bootstrap - Tighten security, enhance configuration flexibility, and improve container startup consistency
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.
Actionable comments posted: 6
♻️ Duplicate comments (2)
deployment/portable/.env.default (1)
7-7
: Good fix: DATABASE_URL now uses the Compose service hostSwitching to
${DATABASE_HOST}
resolves the "localhost inside container" issue flagged earlier.deployment/portable/deploy.sh (1)
142-165
: Hardcoded UID/GID and brittle docker group detectionRepeat of prior feedback: resolve dynamically and write to .env accordingly.
- export DOCKER_UID=1000 - export DOCKER_GID=1000 + export DOCKER_UID=${DOCKER_UID:-$(id -u 2>/dev/null || echo 1000)} + export DOCKER_GID=${DOCKER_GID:-$(id -g 2>/dev/null || echo 1000)} @@ - if command -v getent >/dev/null 2>&1; then - DOCKER_GROUP_ID=$(getent group docker | cut -d: -f3 2>/dev/null || echo "999") - else - # macOS fallback - check if docker group exists in /etc/group - DOCKER_GROUP_ID=$(grep "^docker:" /etc/group 2>/dev/null | cut -d: -f3 || echo "999") - fi + if [ -S /var/run/docker.sock ]; then + if command -v stat >/dev/null 2>&1; then + DOCKER_GROUP_ID=$(stat -c %g /var/run/docker.sock 2>/dev/null || echo "999") + else + DOCKER_GROUP_ID=$(ls -ln /var/run/docker.sock 2>/dev/null | awk '{print $4}' || echo "999") + fi + elif command -v getent >/dev/null 2>&1; then + DOCKER_GROUP_ID=$(getent group docker | cut -d: -f3 2>/dev/null || echo "999") + else + DOCKER_GROUP_ID=$(grep "^docker:" /etc/group 2>/dev/null | cut -d: -f3 || echo "999") + fi @@ - if ! grep -q "DOCKER_UID" .env 2>/dev/null; then - echo "DOCKER_UID=1000" >> .env - fi - if ! grep -q "DOCKER_GID" .env 2>/dev/null; then - echo "DOCKER_GID=1000" >> .env - fi + if ! grep -q "DOCKER_UID" .env 2>/dev/null; then echo "DOCKER_UID=$DOCKER_UID" >> .env; fi + if ! grep -q "DOCKER_GID" .env 2>/dev/null; then echo "DOCKER_GID=$DOCKER_GID" >> .env; fi
🧹 Nitpick comments (5)
deployment/portable/.env.default (1)
6-6
: Drop quotes to satisfy dotenv linters and avoid edge parsingNo spaces present; quotes are unnecessary.
-EMBEDDING_MODEL="bge-small-en-v1.5" +EMBEDDING_MODEL=bge-small-en-v1.5 -REASONING="true" +REASONING=trueAlso applies to: 9-9
start.sh (1)
61-63
: Expose PORT via env and keep logs consistentAvoid hardcoding; many frameworks respect
PORT
.-echo "Starting server on port 3000..." -exec bun server.ts +PORT="${PORT:-3000}" +echo "Starting server on port ${PORT}..." +exec env PORT="$PORT" bun server.tsAlso ensure compose maps container port
${PORT}
and healthchecks target the same.deployment/portable/deploy.sh (3)
136-141
: Prefer .env.default fallback if .env.example is absentPortable repo ships
.env.default
. Add a fallback.-if [ ! -f .env ] && [ -f .env.example ]; then - echo "📋 Copying .env.example to .env..." - cp .env.example .env -fi +if [ ! -f .env ]; then + if [ -f .env.example ]; then + echo "📋 Copying .env.example to .env..." + cp .env.example .env + elif [ -f .env.default ]; then + echo "📋 Copying .env.default to .env..." + cp .env.default .env + fi +fi
335-337
: Prefer --rm to avoid leftover containersStudio runs as a one-off; auto-remove it.
-docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml run -p 4983:4983 app bun drizzle-kit studio +docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml run --rm -p 4983:4983 app bun drizzle-kit studio
9-9
: Harden shell options and gate tracing by DEBUGImprove resilience and avoid secret leakage in logs.
-set -e +set -Eeuo pipefail +[ "${DEBUG:-0}" = "1" ] && set -x
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
.dockerignore
(1 hunks)deployment/portable/.env.default
(1 hunks)deployment/portable/deploy.sh
(1 hunks)start.sh
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- .dockerignore
🧰 Additional context used
🪛 dotenv-linter (3.3.0)
deployment/portable/.env.default
[warning] 3-3: [UnorderedKey] The DOCKER_UID key should go before the VESPA_HOST key
(UnorderedKey)
[warning] 4-4: [UnorderedKey] The DOCKER_GID key should go before the DOCKER_UID key
(UnorderedKey)
[warning] 5-5: [UnorderedKey] The HOST key should go before the VESPA_HOST key
(UnorderedKey)
[warning] 6-6: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 6-6: [UnorderedKey] The EMBEDDING_MODEL key should go before the HOST key
(UnorderedKey)
[warning] 9-9: [QuoteCharacter] The value has quote characters (', ")
(QuoteCharacter)
[warning] 10-10: [UnorderedKey] The GOOGLE_REDIRECT_URI key should go before the POSTGRES_PASSWORD key
(UnorderedKey)
[warning] 11-11: [UnorderedKey] The GOOGLE_CLIENT_ID key should go before the GOOGLE_REDIRECT_URI key
(UnorderedKey)
[warning] 12-12: [UnorderedKey] The GOOGLE_CLIENT_SECRET key should go before the GOOGLE_REDIRECT_URI key
(UnorderedKey)
[warning] 13-13: [UnorderedKey] The ENCRYPTION_KEY key should go before the GOOGLE_CLIENT_ID key
(UnorderedKey)
[warning] 14-14: [UnorderedKey] The JWT_SECRET key should go before the POSTGRES_PASSWORD key
(UnorderedKey)
[warning] 16-16: [UnorderedKey] The AWS_ACCESS_KEY key should go before the ENCRYPTION_KEY key
(UnorderedKey)
[warning] 17-17: [UnorderedKey] The AWS_SECRET_KEY key should go before the ENCRYPTION_KEY key
(UnorderedKey)
[warning] 18-18: [UnorderedKey] The AWS_REGION key should go before the AWS_SECRET_KEY key
(UnorderedKey)
[warning] 19-19: [UnorderedKey] The NODE_ENV key should go before the POSTGRES_PASSWORD key
(UnorderedKey)
🔇 Additional comments (3)
deployment/portable/.env.default (2)
16-18
: AWS var names likely non-standardMost SDKs expect
AWS_ACCESS_KEY_ID
andAWS_SECRET_ACCESS_KEY
. Please confirm your code expects the custom names; if not, rename.-AWS_ACCESS_KEY= -AWS_SECRET_KEY= +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY=
5-5
: Port consistency check (3000 vs 80)
HOST
andGOOGLE_REDIRECT_URI
point to :3000. Ensure compose healthchecks and published ports also use 3000, or adjust one side.Also applies to: 10-10
start.sh (1)
11-17
: Env loaded before readiness checks — goodThis fixes earlier ordering concerns.
…able - Replace hard‑coded `chown 1000:1000` in `deploy.sh` with `USER_UID`/`USER_GID` env vars (defaulting to 1000). - Correctly pass positional argument to `show_logs` command in `deploy.sh`. - Read Vertex AI request timeout from `VERTEX_AI_TIMEOUT` env var (default 4 min) in `vertex_ai.ts`. - Update `start.sh` to use `DATABASE_URL` env var and `${VESPA_HOST:-vespa}` fallback. - Change working directory to `/usr/src/app/server` before running migrations. - Remove hard‑coded host/port in PostgreSQL readiness check for better portability.
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.
Actionable comments posted: 1
🧹 Nitpick comments (5)
start.sh (5)
30-34
: Quote URL and set curl connect timeout.Prevents edge-case parsing issues and fast-fails on dead hosts.
-until curl -f http://${VESPA_HOST:-vespa}:19071/state/v1/health 2>/dev/null; do +until curl -fsS --connect-timeout 2 "http://${VESPA_HOST:-vespa}:19071/state/v1/health" >/dev/null 2>&1; do
41-48
: Optional: add sample data restore on first run.PR summary mentions
data-restore.sh
; hook it here if present/executable.echo "Running database setup..." cd /usr/src/app/server # Try to generate migrations, but don't fail if none exist bun run generate || true # Try to run migrations, but don't fail if none exist bun run migrate || true + + # Restore sample data if a restore script is available (non-fatal on failure) + if [ -x /usr/src/app/deployment/restore-data.sh ]; then + /usr/src/app/deployment/restore-data.sh || echo "⚠️ Data restore script failed" + elif [ -x /usr/src/app/deployment/data-restore.sh ]; then + /usr/src/app/deployment/data-restore.sh || echo "⚠️ Data restore script failed" + else + echo "ℹ️ No data restore script found; skipping" + fi
50-54
: Validate Vespa deploy script availability.Avoid silent failures if script is missing/non-executable.
- cd /usr/src/app/server/vespa - EMBEDDING_MODEL=${EMBEDDING_MODEL:-bge-small-en-v1.5} ./deploy-docker.sh + cd /usr/src/app/server/vespa + if [ -x ./deploy-docker.sh ]; then + EMBEDDING_MODEL=${EMBEDDING_MODEL:-bge-small-en-v1.5} ./deploy-docker.sh + else + echo "⚠️ Vespa deploy script not found or not executable; skipping" + fi
43-44
: Minor: duplicate cd.Already in
/usr/src/app/server
; drop this redundantcd
.- cd /usr/src/app/server
37-61
: Optional: guard one-time init with a file lock.If you ever scale to >1 replica, use
flock
to avoid concurrent migrations/deploys.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
deployment/portable/deploy.sh
(1 hunks)server/ai/provider/vertex_ai.ts
(2 hunks)start.sh
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- deployment/portable/deploy.sh
- server/ai/provider/vertex_ai.ts
🔇 Additional comments (3)
start.sh (3)
2-7
: Good: strict mode + gated tracing.Safer defaults; avoids secret leakage from
-x
.
11-17
: Env loading approach is solid.
allexport
+source
is robust vs. naivexargs
parsing.
63-65
: Use the PORT env var with a sensible default in start.sh
Replace the hard-coded “3000” so the script always honors whatever PORT is set (e.g. via your .env.default in prod) and only falls back to 3000 when none is provided:@@ start.sh:63-65 - echo "Starting server on port 3000..." - exec bun server.ts + RESOLVED_PORT=${PORT:-3000} + echo "Starting server on port ${RESOLVED_PORT}..." + exec env PORT="${RESOLVED_PORT}" bun server.tsThen confirm your deployment/docker-compose.yml env_file (../server/.env.default) declares PORT=80 for production.
…Postgres wait logic - Remove emoji icons and replace with plain `INFO`/`WARNING` prefixes in all deployment scripts - Explicitly construct `DATABASE_URL` from individual environment variables when missing - Add bounded retry loop using `DB_WAIT_MAX_ATTEMPTS` for waiting on PostgreSQL - Simplify initial‑setup logging - Make scripts clearer, easier to parse in CI, and more resilient when environment variables are absent
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.
Actionable comments posted: 1
♻️ Duplicate comments (3)
start.sh (1)
88-90
: Fix app port mismatch (compose expects :80).Container still starts on 3000; compose/healthchecks target 80. Run on 80 (or parameterize with default 80) to avoid broken health/ingress.
-echo "Starting server on port 3000..." -exec bun server.ts +PORT="${PORT:-80}" +echo "Starting server on port ${PORT}..." +exec env PORT="$PORT" bun server.tsdeployment/portable/deploy.sh (2)
142-165
: Hardcoded DOCKER_UID/GID=1000 causes permission drift.Detect from host (or docker.sock) instead. A prior comment flagged this; keeping it here for tracking.
- export DOCKER_UID=1000 - export DOCKER_GID=1000 + export DOCKER_UID=${DOCKER_UID:-$(id -u 2>/dev/null || echo 1000)} + export DOCKER_GID=${DOCKER_GID:-$(id -g 2>/dev/null || echo 1000)} @@ - if command -v getent >/dev/null 2>&1; then - DOCKER_GROUP_ID=$(getent group docker | cut -d: -f3 2>/dev/null || echo "999") - else - # macOS fallback - check if docker group exists in /etc/group - DOCKER_GROUP_ID=$(grep "^docker:" /etc/group 2>/dev/null | cut -d: -f3 || echo "999") - fi + if [ -S /var/run/docker.sock ]; then + if command -v stat >/dev/null 2>&1; then + DOCKER_GROUP_ID=$(stat -c %g /var/run/docker.sock 2>/dev/null || echo "999") + else + DOCKER_GROUP_ID=$(ls -ln /var/run/docker.sock 2>/dev/null | awk '{print $4}' || echo "999") + fi + elif command -v getent >/dev/null 2>&1; then + DOCKER_GROUP_ID=$(getent group docker | cut -d: -f3 2>/dev/null || echo "999") + else + DOCKER_GROUP_ID=$(grep "^docker:" /etc/group 2>/dev/null | cut -d: -f3 || echo "999") + fi @@ - if ! grep -q "DOCKER_UID" .env 2>/dev/null; then - echo "DOCKER_UID=1000" >> .env - fi - if ! grep -q "DOCKER_GID" .env 2>/dev/null; then - echo "DOCKER_GID=1000" >> .env - fi + grep -q "^DOCKER_UID=" .env 2>/dev/null || echo "DOCKER_UID=$DOCKER_UID" >> .env + grep -q "^DOCKER_GID=" .env 2>/dev/null || echo "DOCKER_GID=$DOCKER_GID" >> .env
173-186
: Use resolved UID/GID for chown.Avoid forcing 1000.
- USER_UID="1000" - USER_GID="1000" + USER_UID="${DOCKER_UID:-$(id -u 2>/dev/null || echo 1000)}" + USER_GID="${DOCKER_GID:-$(id -g 2>/dev/null || echo 1000)}"
🧹 Nitpick comments (11)
start.sh (4)
21-21
: Guard working directory change.Fail fast if path is wrong to avoid silent failures later.
-cd /usr/src/app/server +cd /usr/src/app/server || { echo "ERROR: /usr/src/app/server not found"; exit 1; }
55-58
: Harden Vespa health probe (timeouts + quoting).Avoid hangs and quote URL.
-until curl -f http://${VESPA_HOST:-vespa}:19071/state/v1/health 2>/dev/null; do +until curl -fsS --connect-timeout "${VESPA_CONNECT_TIMEOUT:-3}" --max-time "${VESPA_MAX_TIME:-5}" \ + "http://${VESPA_HOST:-vespa}:19071/state/v1/health" >/dev/null 2>&1; do
12-17
: Source .env safely (lint hint).Add ShellCheck suppression for non-constant path; keeps CI linters green.
set -o allexport + # shellcheck disable=SC1091 source /usr/src/app/server/.env
23-31
: DATABASE_URL construction may break with special chars.If password/user contain “@:/?#[]”, the inline URL will be invalid. Prefer providing DATABASE_URL already encoded; only fallback-build for simple creds.
deployment/portable/deploy.sh (5)
9-9
: Enable strict bash mode and gated tracing.Improves reliability and easier debugging via DEBUG=1.
-set -e +set -Eeuo pipefail +[ "${DEBUG:-0}" = "1" ] && set -x
297-303
: Robust app-running check.Match the service state, not a container name substring.
- if ! docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml ps | grep -q "xyne-app.*Up"; then + if ! docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml ps app | grep -q " Up "; thenAlso applies to: 314-319
340-340
: Auto-remove Drizzle Studio container.Prevent lingering containers.
- docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml run -p 4983:4983 app bun drizzle-kit studio + docker-compose -f docker-compose.yml -f "$INFRA_COMPOSE" -f docker-compose.app.yml run --rm -p 4983:4983 app bun drizzle-kit studio
377-377
: Quote positional arg.Avoid word-splitting when passing service name.
- show_logs $1 + show_logs "$1"
346-351
: Prefer healthchecks over fixed sleeps.Leverage compose healthchecks/depends_on: condition=service_healthy instead of sleep 10/5.
Also applies to: 357-365
deployment/portable/use-existing-data.sh (2)
11-11
: Enable strict bash mode.Catches unset vars and pipe failures during in-place edits.
-set -e +set -Eeuo pipefail
53-66
: Sed portability and safety.BSD/GNU sed with “-i.tmp” is fine, but add a trap to restore backups on failure and clarify that “.tmp” is the sed backup (you already keep .backup).
+# Restore backups on error +trap 'echo -e "${RED}Error occurred. Restoring backups...${NC}"; for f in "$file"; do [ -f "$f.backup" ] && mv -f "$f.backup" "$f"; done' ERR
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
deployment/portable/deploy.sh
(1 hunks)deployment/portable/use-existing-data.sh
(1 hunks)start.sh
(1 hunks)
🔇 Additional comments (2)
deployment/portable/deploy.sh (1)
274-275
: Verify published app port in status output.Ensure this matches compose mapping and start.sh (80 vs 3000). Update message if needed.
deployment/portable/use-existing-data.sh (1)
69-74
: Nice utility.Clear, reversible, and scoped edits with backups. LGTM.
- Simplify Dockerfile by removing COPY shared/ /usr/src/app/shared/ - Reduce final image size and build time - Container now contains only server, frontend, and necessary config files
.dockerignore
to exclude node_modules, env files, logs, and build artifactsdata-restore.sh
, sample data archive, andstart.sh
entrypoint that:docker-compose.prod.yml
:promtail-config.yaml
to capture both application and Docker container logssetup-deployment.sh
to:Description
Testing
Additional Notes
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Documentation
Chores