From 9b285d7fecb644811374d2dd350ca3d4c94aeb88 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Mon, 9 Mar 2026 22:17:54 -0400 Subject: [PATCH] feat: implement automated Docker deployment and update README - Replaced manual rsync/npm_deploy workflow with multi-stage Docker builds. - Added Dockerfile and .dockerignore for staging and production environments. - Added 'deploy:staging' and 'deploy:prod' scripts to package.json. - Updated README.md with new deployment instructions. --- .dockerignore | 12 +++++++++ Dockerfile | 46 ++++++++++++++++++++++++++++++++ README.md | 40 +++++++++++++-------------- package.json | 4 ++- src/routes/journals/+page.svelte | 10 ++++++- 5 files changed, 89 insertions(+), 23 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..e1747a4d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +node_modules +build +.svelte-kit +.git +.env +.env.* +!.env.staging +!.env.prod +npm_deploy +test-results +test_results +documentation diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..03abe975 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,46 @@ +# Stage 1: Build the application +# Using node:21-alpine for a lightweight, secure build environment. +FROM node:21-alpine AS builder +WORKDIR /app + +# Install dependencies first for better Docker layer caching. +# This step only reruns if package.json or package-lock.json changes. +COPY package*.json ./ +RUN npm install + +# Copy the rest of the source code. +COPY . . + +# Build Argument to determine build environment (staging, prod, or production). +# Defaults to "staging". +ARG BUILD_MODE=staging +ENV NODE_ENV=production + +# Perform the build based on the BUILD_MODE argument. +# This runs the existing scripts in package.json, which already +# handle copying the correct .env file to .env.production for Vite. +RUN if [ "$BUILD_MODE" = "prod" ] || [ "$BUILD_MODE" = "production" ]; then \ + npm run build:prod; \ + else \ + npm run build:staging; \ + fi + +# Stage 2: Final runtime image +FROM node:21-alpine AS deploy-node +WORKDIR /app + +# Copy only the built files and necessary scripts from the builder stage. +COPY --from=builder /app/build . +COPY --from=builder /app/package.json . + +# Install only production dependencies for a smaller, cleaner image. +RUN npm install --omit=dev + +# Copy the resulting .env.production file to .env. +# adapter-node reads from .env at runtime for non-PUBLIC_ variables. +COPY --from=builder /app/.env.production .env + +# SvelteKit (via adapter-node) defaults to port 3000. +EXPOSE 3000 + +CMD ["node", "index.js"] diff --git a/README.md b/README.md index 978c313a..24fa1732 100644 --- a/README.md +++ b/README.md @@ -123,36 +123,34 @@ Developer sandbox pages — not for production use. # How to build and deploy SvelteKit: -Copy the contents of the "build" directory to ./npm_deploy/build/ +The deployment is now fully automated using Docker Compose. The application is built directly from source inside a clean Docker environment, eliminating the need for manual `rsync` or `npm_deploy` management. +### Commands + +Run these commands from the root of the `aether_app_sveltekit` project: + +#### 1. Deploy to Staging (Dev) +This builds and restarts the staging containers (`ae_app_node_dev`, etc.) on your local workstation. ```bash -npm run build +npm run deploy:staging ``` -If this is just a quick build update then only the build directory needs to be copied (rsync). - +#### 2. Deploy to Production +This builds the image using production flags and restarts the production containers. ```bash -rsync -vhrz --exclude 'node_modules' ~/OSIT_dev/aether_app_sveltekit/build/ ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ --delete - -rsync -vhrz ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ scott@linode.oneskyit.com:/srv/env/prod_aether_sveltekit/npm_deploy/build/ --delete +npm run deploy:prod ``` -If this includes package updates (not development) we need to copy the new package.json. Manually copy the new package.json file to ./npm_deploy/. This also needs to be copied to the server. Copy the package.json even though not really used. +### Technical Details -Run the --omit dev to clear out the node_modules directory. Copy the root node_modules directory to ./npm_deploy/build/node_modules/ after running te omit dev command. +- **Dockerfile**: Uses a multi-stage build. Stage 1 (builder) installs dependencies and builds the app using the `BUILD_MODE` argument. Stage 2 (runtime) creates the final lightweight image. +- **Environment Handling**: + - `PUBLIC_` variables are baked into the image during the build step based on `.env.staging` or `.env.prod`. + - Private runtime variables are passed via the `env_file` in `docker-compose.yml`. +- **Networking**: Containers are automatically joined to the `ae_dev_net` network to allow local Nginx proxying. +- **Legacy Migration**: The `upstream` in the local Nginx configuration has been updated to point to these new SvelteKit containers on port 3000. -```bash -npm ci --omit dev - -# copy/paste, rsync, or cp -rsync -vhrz ~/OSIT_dev/aether_app_sveltekit/node_modules ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ --delete - -# copy package.json as well - -npm install -``` - -Everything should be ready to run on the development server and production server. +--- # Rebuild the node_modules directory and manually install extra Svelte packages diff --git a/package.json b/package.json index 6c53d030..6febf57b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,9 @@ "lint": "prettier --check . && eslint .", "format": "prettier --write .", "test:integration": "playwright test", - "test:unit": "vitest" + "test:unit": "vitest", + "deploy:staging": "docker compose -f ../ae_env_node_app/docker-compose.yml up -d --build --remove-orphans", + "deploy:prod": "docker compose -f ../ae_env_node_app/docker-compose.yml build --build-arg BUILD_MODE=prod && docker compose -f ../ae_env_node_app/docker-compose.yml up -d --remove-orphans" }, "devDependencies": { "@eslint/js": "^9.39.1", diff --git a/src/routes/journals/+page.svelte b/src/routes/journals/+page.svelte index 29af33b3..602f6813 100644 --- a/src/routes/journals/+page.svelte +++ b/src/routes/journals/+page.svelte @@ -20,6 +20,7 @@ // *** Libraries & Stores import { liveQuery } from 'dexie'; import { Modal } from 'flowbite-svelte'; + import { db_core } from '$lib/ae_core/db_core'; import { db_journals } from '$lib/ae_journals/db_journals'; import { journals_func } from '$lib/ae_journals/ae_journals_functions'; import { ae_loc, ae_api, slct } from '$lib/stores/ae_stores'; @@ -47,6 +48,13 @@ let log_lvl = 0; // *** LiveQueries + let lq__account = $derived( + liveQuery(async () => { + if (!$slct.account_id) return null; + return await db_core.account.get($slct.account_id); + }) + ); + let lq__journal_obj_li = $derived( liveQuery(async () => { return await db_journals.journal @@ -105,7 +113,7 @@

Managed by {$ae_loc.account_name ?? 'Æ loading...'}{$lq__account?.name ?? $ae_loc.account_name ?? 'Æ loading...'} {#if $ae_loc.person.given_name} •