Add Docker deployment support for API and Web services
- Add Dockerfiles for API and Web apps with multi-stage builds. - Configure `docker-compose.yml` to manage services (Postgres, API, Web, pgAdmin). - Add `.dockerignore` for optimized builds. - Include `DOCKER_SETUP.md` for deployment steps and guidance.main
parent
8bb8fb8dba
commit
4bc2454f44
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Dependency
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.svelte-kit
|
||||||
|
build
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
.dockerignore
|
||||||
|
|
@ -4,19 +4,7 @@
|
||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="Add user profile management with avatar upload and update support - Create `+page.svelte` for managing user profiles, including name, avatar, and password updates. - Add `Avatar.svelte` component for rendering user avatars with Gravatar and fallback initials support. - Implement backend APIs for fetching and updating user profiles (`/users/profile`). - Add support for avatar uploads with file validation (max size: 5MB). - Update `FloorplanViewer.svelte` to display user names and avatars in reservations. - Introduce utilities for Gravatar URLs and user avatar management (`getGravatarUrl`, `getInitials`).">
|
<list default="true" id="6c8b3c54-eabb-40e5-967f-c7b594c750bc" name="Changes" comment="Update prompts to include progress indicator for documentation readability" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/api/prisma/schema.prisma" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/prisma/schema.prisma" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/api/src/organizations/dto/update-organization.dto.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/organizations/dto/update-organization.dto.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/api/src/users/users.service.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/api/src/users/users.service.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/web/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/package.json" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/components/BookingModal.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/components/BookingModal.svelte" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/web/src/lib/stores/organization.ts" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/lib/stores/organization.ts" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/+layout.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/+layout.svelte" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/admin/organization/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/admin/organization/+page.svelte" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/dashboard/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/dashboard/+page.svelte" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/apps/web/src/routes/dashboard/my-bookings/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/apps/web/src/routes/dashboard/my-bookings/+page.svelte" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||||
|
|
@ -137,7 +125,7 @@
|
||||||
<updated>1774643312599</updated>
|
<updated>1774643312599</updated>
|
||||||
<workItem from="1774643313611" duration="74000" />
|
<workItem from="1774643313611" duration="74000" />
|
||||||
<workItem from="1774643422240" duration="5278000" />
|
<workItem from="1774643422240" duration="5278000" />
|
||||||
<workItem from="1774706361502" duration="9064000" />
|
<workItem from="1774706361502" duration="9383000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="Initialize Hot Desking app with web and API services - Set up SvelteKit for the web interface with Tailwind CSS. - Build the API using NestJS with Prisma ORM for database interaction. - Add environment variable management and docker-compose for PostgreSQL and PgAdmin instances. - Create shared data models for consistent typing across services. - Establish basic routing and layouts for web and API services.">
|
<task id="LOCAL-00001" summary="Initialize Hot Desking app with web and API services - Set up SvelteKit for the web interface with Tailwind CSS. - Build the API using NestJS with Prisma ORM for database interaction. - Add environment variable management and docker-compose for PostgreSQL and PgAdmin instances. - Create shared data models for consistent typing across services. - Establish basic routing and layouts for web and API services.">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
|
|
@ -267,7 +255,23 @@
|
||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1774714977147</updated>
|
<updated>1774714977147</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="17" />
|
<task id="LOCAL-00017" summary="Add i18n support with English and Spanish translations - Introduce `svelte-i18n` for internationalization. - Add English (`en.json`) and Spanish (`es-ES.json`) locale files. - Implement `setupI18n` function for initializing and managing locales. - Update project dependencies to include `svelte-i18n`.">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1774715653258</created>
|
||||||
|
<option name="number" value="00017" />
|
||||||
|
<option name="presentableId" value="LOCAL-00017" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1774715653258</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00018" summary="Update prompts to include progress indicator for documentation readability">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1774715728737</created>
|
||||||
|
<option name="number" value="00018" />
|
||||||
|
<option name="presentableId" value="LOCAL-00018" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1774715728737</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="19" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
|
@ -292,6 +296,8 @@
|
||||||
<MESSAGE value="Add organization management with logo support - Implement organization settings page (`+page.svelte`) for updating organization name and logo. - Create backend APIs for retrieving and updating organization details with role-based access control. - Add `OrganizationsModule`, `OrganizationsService`, and DTOs for input validation in NestJS. - Update Prisma schema to include `logoUrl` field for organizations. - Enhance navigation to dynamically display organization logo and name." />
|
<MESSAGE value="Add organization management with logo support - Implement organization settings page (`+page.svelte`) for updating organization name and logo. - Create backend APIs for retrieving and updating organization details with role-based access control. - Add `OrganizationsModule`, `OrganizationsService`, and DTOs for input validation in NestJS. - Update Prisma schema to include `logoUrl` field for organizations. - Enhance navigation to dynamically display organization logo and name." />
|
||||||
<MESSAGE value="Add assets module with file upload and retrieval support - Introduce `AssetsModule` with APIs for uploading and retrieving organization logos, building images, and floor plans. - Implement file validation for type and size (10MB max). - Add `resolveAssetUrl` utility for generating absolute asset URLs. - Enhance admin UI components to support image file uploads and previews. - Update Prisma schema to associate assets with organizations, buildings, and floors. - Modify existing update logic to clear references when external URLs are used." />
|
<MESSAGE value="Add assets module with file upload and retrieval support - Introduce `AssetsModule` with APIs for uploading and retrieving organization logos, building images, and floor plans. - Implement file validation for type and size (10MB max). - Add `resolveAssetUrl` utility for generating absolute asset URLs. - Enhance admin UI components to support image file uploads and previews. - Update Prisma schema to associate assets with organizations, buildings, and floors. - Modify existing update logic to clear references when external URLs are used." />
|
||||||
<MESSAGE value="Add user profile management with avatar upload and update support - Create `+page.svelte` for managing user profiles, including name, avatar, and password updates. - Add `Avatar.svelte` component for rendering user avatars with Gravatar and fallback initials support. - Implement backend APIs for fetching and updating user profiles (`/users/profile`). - Add support for avatar uploads with file validation (max size: 5MB). - Update `FloorplanViewer.svelte` to display user names and avatars in reservations. - Introduce utilities for Gravatar URLs and user avatar management (`getGravatarUrl`, `getInitials`)." />
|
<MESSAGE value="Add user profile management with avatar upload and update support - Create `+page.svelte` for managing user profiles, including name, avatar, and password updates. - Add `Avatar.svelte` component for rendering user avatars with Gravatar and fallback initials support. - Implement backend APIs for fetching and updating user profiles (`/users/profile`). - Add support for avatar uploads with file validation (max size: 5MB). - Update `FloorplanViewer.svelte` to display user names and avatars in reservations. - Introduce utilities for Gravatar URLs and user avatar management (`getGravatarUrl`, `getInitials`)." />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Add user profile management with avatar upload and update support - Create `+page.svelte` for managing user profiles, including name, avatar, and password updates. - Add `Avatar.svelte` component for rendering user avatars with Gravatar and fallback initials support. - Implement backend APIs for fetching and updating user profiles (`/users/profile`). - Add support for avatar uploads with file validation (max size: 5MB). - Update `FloorplanViewer.svelte` to display user names and avatars in reservations. - Introduce utilities for Gravatar URLs and user avatar management (`getGravatarUrl`, `getInitials`)." />
|
<MESSAGE value="Add i18n support with English and Spanish translations - Introduce `svelte-i18n` for internationalization. - Add English (`en.json`) and Spanish (`es-ES.json`) locale files. - Implement `setupI18n` function for initializing and managing locales. - Update project dependencies to include `svelte-i18n`." />
|
||||||
|
<MESSAGE value="Update prompts to include progress indicator for documentation readability" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Update prompts to include progress indicator for documentation readability" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
# Docker Setup Guide
|
||||||
|
|
||||||
|
This guide describes how to deploy the application using Docker and Docker Compose.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
- Docker (20.10+)
|
||||||
|
- Docker Compose (v2.0+)
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
Create a `.env` file in the root directory. The following variables are supported (with their default values shown):
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `DB_USER` | PostgreSQL username | `postgres` |
|
||||||
|
| `DB_PASSWORD` | PostgreSQL password | `postgres` |
|
||||||
|
| `DB_NAME` | PostgreSQL database name | `hotdesking` |
|
||||||
|
| `DB_PORT_EXTERNAL` | External port for PostgreSQL | `5433` |
|
||||||
|
| `API_PORT_EXTERNAL` | External port for the API | `3000` |
|
||||||
|
| `WEB_PORT_EXTERNAL` | External port for the Web app | `5173` |
|
||||||
|
| `JWT_SECRET` | Secret key for JWT signing | `super-secret-change-me` |
|
||||||
|
| `WEB_ORIGIN` | The origin of the web app (required by SvelteKit) | `http://localhost:5173` |
|
||||||
|
| `VITE_API_BASE_URL` | The URL of the API (for the web app) | `http://localhost:3000` |
|
||||||
|
|
||||||
|
## Deployment Steps
|
||||||
|
|
||||||
|
1. **Build and start the containers:**
|
||||||
|
```bash
|
||||||
|
docker-compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Run Database Migrations:**
|
||||||
|
Since the API uses Prisma, you need to run migrations to set up the database schema:
|
||||||
|
```bash
|
||||||
|
docker exec -it hotdesking_api npx prisma migrate deploy
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **(Optional) Seed the Database:**
|
||||||
|
If you have a seed script defined in `apps/api/prisma/seed.ts`:
|
||||||
|
```bash
|
||||||
|
docker exec -it hotdesking_api npx prisma db seed
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Access the Applications:**
|
||||||
|
- Web App: [http://localhost:5173](http://localhost:5173)
|
||||||
|
- API: [http://localhost:3000](http://localhost:3000)
|
||||||
|
- pgAdmin: [http://localhost:5051](http://localhost:5051) (Login: `admin@local.dev` / `admin`)
|
||||||
|
|
||||||
|
## Development with Docker
|
||||||
|
|
||||||
|
To watch logs:
|
||||||
|
```bash
|
||||||
|
docker-compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
To stop the applications:
|
||||||
|
```bash
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy root configs
|
||||||
|
COPY package*.json ./
|
||||||
|
COPY tsconfig.json ./
|
||||||
|
COPY tsconfig.base.json ./
|
||||||
|
|
||||||
|
# Copy packages
|
||||||
|
COPY apps/api/package*.json ./apps/api/
|
||||||
|
COPY shared/package*.json ./shared/
|
||||||
|
|
||||||
|
# Install dependencies (using npm ci for better builds)
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY apps/api ./apps/api
|
||||||
|
COPY shared ./shared
|
||||||
|
|
||||||
|
# Generate Prisma client
|
||||||
|
WORKDIR /app/apps/api
|
||||||
|
RUN npx prisma generate
|
||||||
|
|
||||||
|
# Build the app
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ---
|
||||||
|
FROM node:20-alpine AS runner
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy build artifacts and necessary files
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder /app/apps/api/node_modules ./apps/api/node_modules
|
||||||
|
COPY --from=builder /app/apps/api/dist ./apps/api/dist
|
||||||
|
COPY --from=builder /app/apps/api/package.json ./apps/api/package.json
|
||||||
|
COPY --from=builder /app/apps/api/prisma ./apps/api/prisma
|
||||||
|
COPY --from=builder /app/shared/dist ./shared/dist
|
||||||
|
COPY --from=builder /app/shared/package.json ./shared/package.json
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
ENV PORT=3000
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
WORKDIR /app/apps/api
|
||||||
|
CMD ["node", "dist/main"]
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy root configs
|
||||||
|
COPY package*.json ./
|
||||||
|
COPY tsconfig.json ./
|
||||||
|
COPY tsconfig.base.json ./
|
||||||
|
|
||||||
|
# Copy packages
|
||||||
|
COPY apps/web/package*.json ./apps/web/
|
||||||
|
COPY shared/package*.json ./shared/
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY apps/web ./apps/web
|
||||||
|
COPY shared ./shared
|
||||||
|
|
||||||
|
# Build the app
|
||||||
|
WORKDIR /app/apps/web
|
||||||
|
# We need VITE_API_BASE_URL at build time for SvelteKit static replacements if any,
|
||||||
|
# but usually it's better to use dynamic env vars if possible.
|
||||||
|
# For now, let's assume it can be provided during build or we use the default.
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# ---
|
||||||
|
FROM node:20-alpine AS runner
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy build artifacts and necessary files
|
||||||
|
COPY --from=builder /app/apps/web/build ./apps/web/build
|
||||||
|
COPY --from=builder /app/apps/web/package.json ./apps/web/package.json
|
||||||
|
# Node adapter needs dependencies to run
|
||||||
|
COPY --from=builder /app/node_modules ./node_modules
|
||||||
|
|
||||||
|
EXPOSE 5173
|
||||||
|
|
||||||
|
ENV PORT=5173
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
WORKDIR /app/apps/web
|
||||||
|
CMD ["node", "build"]
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-auto": "^3.3.1",
|
"@sveltejs/adapter-node": "^5.2.11",
|
||||||
"@sveltejs/kit": "^2.0.0",
|
"@sveltejs/kit": "^2.0.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
"@sveltejs/vite-plugin-svelte": "^4.0.0",
|
||||||
"autoprefixer": "^10.4.0",
|
"autoprefixer": "^10.4.0",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import adapter from '@sveltejs/adapter-auto';
|
import adapter from '@sveltejs/adapter-node';
|
||||||
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
/** @type {import('@sveltejs/kit').Config} */
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,47 @@
|
||||||
version: "3.9"
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:16
|
image: postgres:16
|
||||||
container_name: hotdesking_postgres
|
container_name: hotdesking_postgres
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: ${DB_USER:-postgres}
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres}
|
||||||
POSTGRES_DB: hotdesking
|
POSTGRES_DB: ${DB_NAME:-hotdesking}
|
||||||
ports:
|
ports:
|
||||||
- "5433:5432"
|
- "${DB_PORT_EXTERNAL:-5433}:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: apps/api/Dockerfile
|
||||||
|
container_name: hotdesking_api
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${API_PORT_EXTERNAL:-3000}:3000"
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: "postgresql://${DB_USER:-postgres}:${DB_PASSWORD:-postgres}@postgres:5432/${DB_NAME:-hotdesking}"
|
||||||
|
PORT: 3000
|
||||||
|
JWT_SECRET: ${JWT_SECRET:-super-secret-change-me}
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
|
||||||
|
web:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: apps/web/Dockerfile
|
||||||
|
container_name: hotdesking_web
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${WEB_PORT_EXTERNAL:-5173}:5173"
|
||||||
|
environment:
|
||||||
|
PORT: 5173
|
||||||
|
ORIGIN: ${WEB_ORIGIN:-http://localhost:5173}
|
||||||
|
VITE_API_BASE_URL: ${VITE_API_BASE_URL:-http://localhost:3000}
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
|
||||||
pgadmin:
|
pgadmin:
|
||||||
image: dpage/pgadmin4:8
|
image: dpage/pgadmin4:8
|
||||||
container_name: hotdesking_pgadmin
|
container_name: hotdesking_pgadmin
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue