mirror of
https://github.com/kyantech/Palmr.git
synced 2025-10-23 06:11:58 +00:00
chore: add Dockerfile, docker-compose, and .dockerignore for multi-service setup
Introduce a Dockerfile for building the Palmr application with multi-stage builds for both server and web components. Update docker-compose.yaml to consolidate services under a single 'palmr' service, ensuring proper health checks and environment variable configurations. Add a .dockerignore file to optimize Docker builds by excluding unnecessary files. Include a Makefile for simplified build and deployment commands.
This commit is contained in:
70
.dockerignore
Normal file
70
.dockerignore
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
README.md
|
||||||
|
CONTRIBUTING.md
|
||||||
|
*.md
|
||||||
|
|
||||||
|
# Node modules
|
||||||
|
node_modules
|
||||||
|
*/node_modules
|
||||||
|
**/node_modules
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
.next
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
|
||||||
|
# Development files
|
||||||
|
.env*
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# Docker files
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
160
Dockerfile
Normal file
160
Dockerfile
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
FROM node:18-alpine AS base
|
||||||
|
|
||||||
|
# Install system dependencies
|
||||||
|
RUN apk add --no-cache \
|
||||||
|
netcat-openbsd \
|
||||||
|
gcompat \
|
||||||
|
supervisor \
|
||||||
|
curl
|
||||||
|
|
||||||
|
# Enable pnpm
|
||||||
|
RUN corepack enable pnpm
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# === SERVER BUILD STAGE ===
|
||||||
|
FROM base AS server-deps
|
||||||
|
WORKDIR /app/server
|
||||||
|
|
||||||
|
# Copy server package files
|
||||||
|
COPY apps/server/package*.json ./
|
||||||
|
COPY apps/server/pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
# Install server dependencies
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
FROM base AS server-builder
|
||||||
|
WORKDIR /app/server
|
||||||
|
|
||||||
|
# Copy server dependencies
|
||||||
|
COPY --from=server-deps /app/server/node_modules ./node_modules
|
||||||
|
|
||||||
|
# Copy server source code
|
||||||
|
COPY apps/server/ ./
|
||||||
|
|
||||||
|
# Generate Prisma client
|
||||||
|
RUN npx prisma generate
|
||||||
|
|
||||||
|
# Build server
|
||||||
|
RUN pnpm build
|
||||||
|
|
||||||
|
# === WEB BUILD STAGE ===
|
||||||
|
FROM base AS web-deps
|
||||||
|
WORKDIR /app/web
|
||||||
|
|
||||||
|
# Copy web package files
|
||||||
|
COPY apps/web/package.json apps/web/pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
# Install web dependencies
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
FROM base AS web-builder
|
||||||
|
WORKDIR /app/web
|
||||||
|
|
||||||
|
# Copy web dependencies
|
||||||
|
COPY --from=web-deps /app/web/node_modules ./node_modules
|
||||||
|
|
||||||
|
# Copy web source code
|
||||||
|
COPY apps/web/ ./
|
||||||
|
|
||||||
|
# Set environment variables for build
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
# Build web application
|
||||||
|
RUN pnpm run build
|
||||||
|
|
||||||
|
# === PRODUCTION STAGE ===
|
||||||
|
FROM base AS runner
|
||||||
|
|
||||||
|
# Set production environment
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
|
||||||
|
# Create application user
|
||||||
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
|
RUN adduser --system --uid 1001 palmr
|
||||||
|
|
||||||
|
# Create application directories and set permissions
|
||||||
|
RUN mkdir -p /app/server /app/web /home/palmr/.npm /home/palmr/.cache
|
||||||
|
RUN chown -R palmr:nodejs /app /home/palmr
|
||||||
|
|
||||||
|
# === Copy Server Files ===
|
||||||
|
WORKDIR /app/server
|
||||||
|
|
||||||
|
# Copy server production files
|
||||||
|
COPY --from=server-builder --chown=palmr:nodejs /app/server/dist ./dist
|
||||||
|
COPY --from=server-builder --chown=palmr:nodejs /app/server/node_modules ./node_modules
|
||||||
|
COPY --from=server-builder --chown=palmr:nodejs /app/server/prisma ./prisma
|
||||||
|
COPY --from=server-builder --chown=palmr:nodejs /app/server/package.json ./
|
||||||
|
|
||||||
|
# === Copy Web Files ===
|
||||||
|
WORKDIR /app/web
|
||||||
|
|
||||||
|
# Copy web production files
|
||||||
|
COPY --from=web-builder --chown=palmr:nodejs /app/web/public ./public
|
||||||
|
COPY --from=web-builder --chown=palmr:nodejs /app/web/.next/standalone ./
|
||||||
|
COPY --from=web-builder --chown=palmr:nodejs /app/web/.next/static ./.next/static
|
||||||
|
|
||||||
|
# === Setup Supervisor ===
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Create supervisor configuration
|
||||||
|
RUN mkdir -p /etc/supervisor/conf.d /var/log/supervisor
|
||||||
|
|
||||||
|
# Copy server start script
|
||||||
|
COPY infra/server-start.sh /app/server-start.sh
|
||||||
|
RUN chmod +x /app/server-start.sh
|
||||||
|
RUN chown palmr:nodejs /app/server-start.sh
|
||||||
|
|
||||||
|
# Copy supervisor configuration
|
||||||
|
COPY <<EOF /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
logfile=/var/log/supervisor/supervisord.log
|
||||||
|
pidfile=/var/run/supervisord.pid
|
||||||
|
|
||||||
|
[program:server]
|
||||||
|
command=/app/server-start.sh
|
||||||
|
directory=/app/server
|
||||||
|
user=palmr
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stderr_logfile=/var/log/supervisor/server.err.log
|
||||||
|
stdout_logfile=/var/log/supervisor/server.out.log
|
||||||
|
environment=PORT=3333,HOME="/home/palmr"
|
||||||
|
|
||||||
|
[program:web]
|
||||||
|
command=node server.js
|
||||||
|
directory=/app/web
|
||||||
|
user=palmr
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
stderr_logfile=/var/log/supervisor/web.err.log
|
||||||
|
stdout_logfile=/var/log/supervisor/web.out.log
|
||||||
|
environment=PORT=5487,HOSTNAME="0.0.0.0",HOME="/home/palmr"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create main startup script
|
||||||
|
COPY <<EOF /app/start.sh
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Starting Palmr Application..."
|
||||||
|
|
||||||
|
# Start supervisor
|
||||||
|
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN chmod +x /app/start.sh
|
||||||
|
|
||||||
|
# Expose ports
|
||||||
|
EXPOSE 3333 5487
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||||
|
CMD curl -f http://localhost:5487 || exit 1
|
||||||
|
|
||||||
|
# Start application
|
||||||
|
CMD ["/app/start.sh"]
|
47
Makefile
Normal file
47
Makefile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
.PHONY: help build start clean logs stop restart
|
||||||
|
|
||||||
|
# Default target
|
||||||
|
help:
|
||||||
|
@echo "🚀 Palmr - Available Commands:"
|
||||||
|
@echo ""
|
||||||
|
@echo " make build - Build Docker image with multi-platform support"
|
||||||
|
@echo " make start - Start the application using docker-compose"
|
||||||
|
@echo " make stop - Stop all running containers"
|
||||||
|
@echo " make logs - Show application logs"
|
||||||
|
@echo " make clean - Clean up containers and images"
|
||||||
|
@echo " make shell - Access the application container shell"
|
||||||
|
@echo ""
|
||||||
|
@echo "📁 Scripts location: ./infra/"
|
||||||
|
|
||||||
|
# Build Docker image using the build script
|
||||||
|
build:
|
||||||
|
@echo "🏗️ Building Palmr Docker image..."
|
||||||
|
@chmod +x ./infra/build-docker.sh
|
||||||
|
@./infra/build-docker.sh
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
start:
|
||||||
|
@echo "🚀 Starting Palmr application..."
|
||||||
|
@docker-compose up -d
|
||||||
|
|
||||||
|
# Stop the application
|
||||||
|
stop:
|
||||||
|
@echo "🛑 Stopping Palmr application..."
|
||||||
|
@docker-compose down
|
||||||
|
|
||||||
|
# Show logs
|
||||||
|
logs:
|
||||||
|
@echo "📋 Showing Palmr logs..."
|
||||||
|
@docker-compose logs -f
|
||||||
|
|
||||||
|
# Clean up containers and images
|
||||||
|
clean:
|
||||||
|
@echo "🧹 Cleaning up Docker containers and images..."
|
||||||
|
@docker-compose down -v
|
||||||
|
@docker system prune -f
|
||||||
|
@echo "✅ Cleanup completed!"
|
||||||
|
|
||||||
|
# Access container shell
|
||||||
|
shell:
|
||||||
|
@echo "🐚 Accessing Palmr container shell..."
|
||||||
|
@docker-compose exec palmr /bin/sh
|
@@ -29,15 +29,16 @@ Below is the complete content of our `docker-compose.yaml` that can be copied di
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
palmr-api:
|
palmr:
|
||||||
image: kyantech/palmr-api:latest # Make sure to use the correct version (latest) of the image
|
image: kyantech/palmr:latest # Make sure to use the correct version (latest) of the image
|
||||||
container_name: palmr-api
|
container_name: palmr
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: "service_healthy"
|
condition: "service_healthy"
|
||||||
minio:
|
minio:
|
||||||
condition: "service_healthy"
|
condition: "service_healthy"
|
||||||
environment:
|
environment:
|
||||||
|
# Server environment variables
|
||||||
- PORT=${API_INTERNAL_PORT:-3333} # Port for the backend service
|
- PORT=${API_INTERNAL_PORT:-3333} # Port for the backend service
|
||||||
- DATABASE_URL=postgresql://postgres:${POSTGRESQL_PASSWORD:-postgresRootPassword}@postgres:5432/palmr_db?schema=public # Database URL with configurable password through POSTGRESQL_PASSWORD env var
|
- DATABASE_URL=postgresql://postgres:${POSTGRESQL_PASSWORD:-postgresRootPassword}@postgres:5432/palmr_db?schema=public # Database URL with configurable password through POSTGRESQL_PASSWORD env var
|
||||||
- MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio} # This can change if your MinIO is at a different address
|
- MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio} # This can change if your MinIO is at a different address
|
||||||
@@ -50,34 +51,21 @@ services:
|
|||||||
- FRONTEND_URL=${APP_URL:-http://${SERVER_IP:-localhost}:${APP_EXTERNAL_PORT:-5487}} # Frontend URL - Make sure to use the correct frontend URL, depends on where the frontend is running, its prepared for localhost, but you can change it to your frontend URL if needed
|
- FRONTEND_URL=${APP_URL:-http://${SERVER_IP:-localhost}:${APP_EXTERNAL_PORT:-5487}} # Frontend URL - Make sure to use the correct frontend URL, depends on where the frontend is running, its prepared for localhost, but you can change it to your frontend URL if needed
|
||||||
- SERVER_IP=${SERVER_IP:-localhost} # Server IP - Make sure to use the correct server IP if you running on a cloud provider or a virtual machine. This prepared for localhost, but you can change it to your server IP if needed
|
- SERVER_IP=${SERVER_IP:-localhost} # Server IP - Make sure to use the correct server IP if you running on a cloud provider or a virtual machine. This prepared for localhost, but you can change it to your server IP if needed
|
||||||
- MAX_FILESIZE=${MAX_FILESIZE:-1073741824} # Max Filesize for upload - Declared in Bytes. Default is 1GiB
|
- MAX_FILESIZE=${MAX_FILESIZE:-1073741824} # Max Filesize for upload - Declared in Bytes. Default is 1GiB
|
||||||
ports:
|
|
||||||
- "${API_EXTERNAL_PORT:-3333}:${API_INTERNAL_PORT:-3333}" # Backend port mapping
|
# Web environment variables
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "--no-verbose", "http://palmr-api:${API_INTERNAL_PORT:-3333}/health"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 30s
|
|
||||||
|
|
||||||
palmr-app:
|
|
||||||
image: kyantech/palmr-app:latest # Make sure to use the correct version (latest) of the image
|
|
||||||
container_name: palmr-web
|
|
||||||
depends_on:
|
|
||||||
palmr-api:
|
|
||||||
condition: "service_healthy"
|
|
||||||
ports:
|
|
||||||
- "${APP_EXTERNAL_PORT:-5487}:5487" # Frontend port mapping
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- NEXT_TELEMETRY_DISABLED=1
|
- NEXT_TELEMETRY_DISABLED=1
|
||||||
- API_BASE_URL=http://palmr-api:${API_INTERNAL_PORT:-3333} # Here we use docker's internal network to reference the backend service (can be changed if needed)
|
- API_BASE_URL=http://palmr:${API_INTERNAL_PORT:-3333} # Using Docker service name for internal communication
|
||||||
|
ports:
|
||||||
|
- "${API_EXTERNAL_PORT:-3333}:3333" # Server port
|
||||||
|
- "${APP_EXTERNAL_PORT:-5487}:5487" # Web port
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:5487"]
|
test: ["CMD", "curl", "-f", "http://localhost:3333/health", "&&", "curl", "-f", "http://localhost:5487"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
minio:
|
minio:
|
||||||
image: minio/minio:RELEASE.2025-03-12T18-04-18Z # Use only version RELEASE.2025-03-12T18-04-18Z to avoid compatibility issues with the backend
|
image: minio/minio:RELEASE.2025-03-12T18-04-18Z # Use only version RELEASE.2025-03-12T18-04-18Z to avoid compatibility issues with the backend
|
||||||
@@ -138,7 +126,7 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
minio_data:
|
minio_data:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -148,12 +136,11 @@ Notice that the `docker-compose.yaml` has several comments that help you configu
|
|||||||
|
|
||||||
### ⚙️ Services Overview
|
### ⚙️ Services Overview
|
||||||
|
|
||||||
Palmr. consists of five main services, each with specific responsibilities. Below, we present a detailed view of each component:
|
Palmr. consists of four main services, each with specific responsibilities. Below, we present a detailed view of each component:
|
||||||
|
|
||||||
| **Service** | **Image** | **Exposed Ports** | **Main Features** |
|
| **Service** | **Image** | **Exposed Ports** | **Main Features** |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| palmr-api (Backend) | [kyantech/palmr-api:latest](https://hub.docker.com/repository/docker/kyantech/palmr-api/tags/latest/sha256-84245d3d0012aa65c588caba56322363729c4b68c3722a08dcda912904de9d1d) | **3333** | • Main API service<br/>• Depends on services: postgres and minio<br/>• Has healthcheck to ensure availability |
|
| palmr | [kyantech/palmr:latest](https://hub.docker.com/repository/docker/kyantech/palmr/general) | **3333** (API)<br/>**5487** (Web) | • Combined backend API and frontend service<br/>• Depends on services: postgres and minio<br/>• Has healthcheck to ensure availability |
|
||||||
| palmr-app (Frontend) | [kyantech/palmr-app:latest](https://hub.docker.com/repository/docker/kyantech/palmr-app/tags/latest/sha256-33f568673ae8cc8529532146b6afc1acafa203387ced6c7bb3451a7ab4198a2f) | **5487** | • Web application interface<br/>• Depends on palmr-api service<br/>• Configured for production environment |
|
|
||||||
| minio (Storage) | [minio/minio:RELEASE.2025-03-12T18-04-18Z](https://hub.docker.com/layers/minio/minio/RELEASE.2025-03-12T18-04-18Z/images/sha256-85f3e4cd1ca92a2711553ab79f222bcd8b75aa2c77a1a0b0ccf80d38e8ab2fe5) | **6421**(API)<br/>**6422**(Console) | • File storage service<br/>• Persistent volume for data |
|
| minio (Storage) | [minio/minio:RELEASE.2025-03-12T18-04-18Z](https://hub.docker.com/layers/minio/minio/RELEASE.2025-03-12T18-04-18Z/images/sha256-85f3e4cd1ca92a2711553ab79f222bcd8b75aa2c77a1a0b0ccf80d38e8ab2fe5) | **6421**(API)<br/>**6422**(Console) | • File storage service<br/>• Persistent volume for data |
|
||||||
| minio-init (Config) | [minio/mc:RELEASE.2025-03-12T17-29-24Z](https://hub.docker.com/layers/minio/mc/RELEASE.2025-03-12T17-29-24Z/images/sha256-68d8c80f43908b02daa285e55547131870a1d36b3ffe272c26d7d8f4d52d1e5c) | N/A | • Initially configures the "files" bucket<br/>• Runs only once during initialization |
|
| minio-init (Config) | [minio/mc:RELEASE.2025-03-12T17-29-24Z](https://hub.docker.com/layers/minio/mc/RELEASE.2025-03-12T17-29-24Z/images/sha256-68d8c80f43908b02daa285e55547131870a1d36b3ffe272c26d7d8f4d52d1e5c) | N/A | • Initially configures the "files" bucket<br/>• Runs only once during initialization |
|
||||||
| postgres (Database) | [bitnami/postgresql:17.2.0](https://hub.docker.com/layers/bitnami/postgresql/17.2.0/images/sha256-29c614afad4f514b12b5c0f4d006f38c98fa4b18c3582732ff93b3fe9a79d875) | **5432** | • PostgreSQL database<br/>• Persistent volume for data |
|
| postgres (Database) | [bitnami/postgresql:17.2.0](https://hub.docker.com/layers/bitnami/postgresql/17.2.0/images/sha256-29c614afad4f514b12b5c0f4d006f38c98fa4b18c3582732ff93b3fe9a79d875) | **5432** | • PostgreSQL database<br/>• Persistent volume for data |
|
||||||
@@ -197,13 +184,17 @@ The table below shows all environment variables that can be set
|
|||||||
|
|
||||||
In a localhost environment, there's no mystery. If you don't want to change any service exposure ports, you can simply run:
|
In a localhost environment, there's no mystery. If you don't want to change any service exposure ports, you can simply run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose pull && docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
This will execute all necessary services and give you access to the following URLs (if you haven't changed any ports):
|
This will execute all necessary services and give you access to the following URLs (if you haven't changed any ports):
|
||||||
|
|
||||||
- **Frontend:** [http://localhost:5487](http://localhost:5487)
|
- **Frontend:** [http://localhost:5487](http://localhost:5487)
|
||||||
- **Backend:** [http://localhost:3333](http://localhost:3333/)
|
- **Backend:** [http://localhost:3333](http://localhost:3333/)
|
||||||
- **MinIO API:** [http://localhost:6421](http://localhost:6421)
|
- **MinIO API:** [http://localhost:6421](http://localhost:6421)
|
||||||
- **MinIO Console:** [http://localhost:6422](http://localhost:6422)
|
- **MinIO Console:** [http://localhost:6422](http://localhost:6422)
|
||||||
- **Postgres Database:** [http://localhost:5423](http://localhost:5423/) (Connection only)
|
- **Postgres Database:** [http://localhost:5432](http://localhost:5432/) (Connection only)
|
||||||
|
|
||||||
> *If you have changed any port, simply access the URL with the port you configured.*
|
> *If you have changed any port, simply access the URL with the port you configured.*
|
||||||
>
|
>
|
||||||
@@ -247,7 +238,7 @@ If you haven't changed the execution ports, you'll have access on your server at
|
|||||||
- **Backend:** `[server_ip]:3333`
|
- **Backend:** `[server_ip]:3333`
|
||||||
- **MinIO API:** `[server_ip]:6421`
|
- **MinIO API:** `[server_ip]:6421`
|
||||||
- **MinIO Console:** `[server_ip]:6422`
|
- **MinIO Console:** `[server_ip]:6422`
|
||||||
- **Postgres Database:** `[server_ip]:5423` (Connection only)
|
- **Postgres Database:** `[server_ip]:5432` (Connection only)
|
||||||
|
|
||||||
> *If you've changed any port, simply access the URL with the port you configured.*
|
> *If you've changed any port, simply access the URL with the port you configured.*
|
||||||
>
|
>
|
||||||
|
@@ -25,4 +25,4 @@
|
|||||||
"gh-sponsor",
|
"gh-sponsor",
|
||||||
"..."
|
"..."
|
||||||
]
|
]
|
||||||
}
|
}
|
@@ -83,7 +83,12 @@ export default function HomePage() {
|
|||||||
function Hero() {
|
function Hero() {
|
||||||
return (
|
return (
|
||||||
<section className="relative z-[2] flex flex-col border-x border-t px-6 pt-12 pb-10 md:px-12 md:pt-16 max-md:text-center">
|
<section className="relative z-[2] flex flex-col border-x border-t px-6 pt-12 pb-10 md:px-12 md:pt-16 max-md:text-center">
|
||||||
<h1 className="mb-8 text-5xl font-bold">🌴 Palmr. <span className="text-[10px] font-light text-muted-foreground/50 font-mono">v2.0.0-beta</span></h1>
|
<h1 className="mb-8 text-5xl font-bold">
|
||||||
|
🌴 Palmr.{" "}
|
||||||
|
<span className="text-[10px] font-light text-muted-foreground/50 font-mono">
|
||||||
|
v2.0.0-beta
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
<h1 className="hidden text-4xl font-medium max-w-[600px] md:block mb-4">
|
<h1 className="hidden text-4xl font-medium max-w-[600px] md:block mb-4">
|
||||||
Modern & efficient file sharing
|
Modern & efficient file sharing
|
||||||
</h1>
|
</h1>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { source } from '@/lib/source';
|
import { source } from "@/lib/source";
|
||||||
import { createFromSource } from 'fumadocs-core/search/server';
|
import { createFromSource } from "fumadocs-core/search/server";
|
||||||
|
|
||||||
export const { GET } = createFromSource(source, (page) => {
|
export const { GET } = createFromSource(source, (page) => {
|
||||||
return {
|
return {
|
||||||
title: page.data.title,
|
title: page.data.title,
|
||||||
@@ -8,6 +8,8 @@ export const { GET } = createFromSource(source, (page) => {
|
|||||||
url: page.url,
|
url: page.url,
|
||||||
id: page.url,
|
id: page.url,
|
||||||
structuredData: page.data.structuredData,
|
structuredData: page.data.structuredData,
|
||||||
tag: page.url.startsWith('/docs/2.0.0-beta') ? 'v2.0.0-beta' : 'v1.1.7-beta'
|
tag: page.url.startsWith("/docs/2.0.0-beta")
|
||||||
|
? "v2.0.0-beta"
|
||||||
|
: "v1.1.7-beta",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@@ -11,14 +11,15 @@ const inter = Inter({
|
|||||||
|
|
||||||
export const metadata = {
|
export const metadata = {
|
||||||
title: "🌴 Palmr. | Official Website",
|
title: "🌴 Palmr. | Official Website",
|
||||||
description: "Palmr. is a fast, simple and powerful document sharing platform.",
|
description:
|
||||||
|
"Palmr. is a fast, simple and powerful document sharing platform.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Layout({ children }: { children: ReactNode }) {
|
export default function Layout({ children }: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<html lang="en" className={inter.className} suppressHydrationWarning>
|
<html lang="en" className={inter.className} suppressHydrationWarning>
|
||||||
<body className="flex flex-col min-h-screen">
|
<body className="flex flex-col min-h-screen">
|
||||||
<Banner variant="rainbow" id="banner-v-2">
|
<Banner variant="rainbow" id="banner-v-3">
|
||||||
<Link href="/docs/2.0.0-beta">Palmr. v2.0.0-beta has released!</Link>
|
<Link href="/docs/2.0.0-beta">Palmr. v2.0.0-beta has released!</Link>
|
||||||
</Banner>
|
</Banner>
|
||||||
<RootProvider
|
<RootProvider
|
||||||
|
@@ -11,7 +11,10 @@
|
|||||||
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
|
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
|
||||||
"format": "prettier . --write",
|
"format": "prettier . --write",
|
||||||
"format:check": "prettier . --check",
|
"format:check": "prettier . --check",
|
||||||
"db:seed": "ts-node prisma/seed.ts"
|
"db:seed": "ts-node prisma/seed.js"
|
||||||
|
},
|
||||||
|
"prisma": {
|
||||||
|
"seed": "node prisma/seed.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
import { prisma } from "../src/shared/prisma";
|
/* eslint-disable no-undef */
|
||||||
import crypto from "node:crypto";
|
const { PrismaClient } = require('@prisma/client');
|
||||||
import { env } from '../src/env';
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
const defaultConfigs = [
|
const defaultConfigs = [
|
||||||
// General Configurations
|
// General Configurations
|
||||||
@@ -37,7 +39,7 @@ const defaultConfigs = [
|
|||||||
// Storage Configurations
|
// Storage Configurations
|
||||||
{
|
{
|
||||||
key: "maxFileSize",
|
key: "maxFileSize",
|
||||||
value: env.MAX_FILESIZE, // default 1GiB in bytes - 1073741824
|
value: process.env.MAX_FILESIZE || "1073741824", // default 1GiB in bytes
|
||||||
type: "bigint",
|
type: "bigint",
|
||||||
group: "storage",
|
group: "storage",
|
||||||
},
|
},
|
||||||
@@ -124,28 +126,37 @@ const defaultConfigs = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log("Seeding app configurations...");
|
console.log("🌱 Starting app configurations seed...");
|
||||||
|
console.log("🛡️ Protected mode: Only creates missing configurations");
|
||||||
|
|
||||||
|
let createdCount = 0;
|
||||||
|
let skippedCount = 0;
|
||||||
|
|
||||||
for (const config of defaultConfigs) {
|
for (const config of defaultConfigs) {
|
||||||
if (config.key === "jwtSecret") {
|
// Check if configuration already exists
|
||||||
const existingSecret = await prisma.appConfig.findUnique({
|
const existingConfig = await prisma.appConfig.findUnique({
|
||||||
where: { key: "jwtSecret" },
|
where: { key: config.key },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existingSecret) {
|
if (existingConfig) {
|
||||||
console.log("JWT secret already exists, skipping...");
|
console.log(`⏭️ Configuration '${config.key}' already exists, skipping...`);
|
||||||
continue;
|
skippedCount++;
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
await prisma.appConfig.upsert({
|
// Only create if it doesn't exist
|
||||||
where: { key: config.key },
|
await prisma.appConfig.create({
|
||||||
update: config,
|
data: config,
|
||||||
create: config,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(`✅ Created configuration: ${config.key}`);
|
||||||
|
createdCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("App configurations seeded successfully!");
|
console.log("\n📊 Seed Summary:");
|
||||||
|
console.log(` ✅ Created: ${createdCount} configurations`);
|
||||||
|
console.log(` ⏭️ Skipped: ${skippedCount} configurations`);
|
||||||
|
console.log("🎉 App configurations seeded successfully!");
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
@@ -155,4 +166,4 @@ main()
|
|||||||
})
|
})
|
||||||
.finally(async () => {
|
.finally(async () => {
|
||||||
await prisma.$disconnect();
|
await prisma.$disconnect();
|
||||||
});
|
});
|
@@ -1,17 +0,0 @@
|
|||||||
import { PrismaClient } from '@prisma/client';
|
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const count = await prisma.user.count();
|
|
||||||
console.log(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
main()
|
|
||||||
.catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
})
|
|
||||||
.finally(async () => {
|
|
||||||
await prisma.$disconnect();
|
|
||||||
});
|
|
@@ -1,27 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
echo "Waiting for PostgreSQL..."
|
|
||||||
while ! nc -z postgres 5432; do
|
|
||||||
sleep 1
|
|
||||||
done
|
|
||||||
echo "PostgreSQL is up!"
|
|
||||||
|
|
||||||
echo "Generating Prisma client..."
|
|
||||||
npx prisma generate --schema=./prisma/schema.prisma
|
|
||||||
|
|
||||||
# Check if database needs migrations
|
|
||||||
echo "Checking migrations..."
|
|
||||||
npx prisma migrate deploy
|
|
||||||
|
|
||||||
# Check if database is empty using Prisma
|
|
||||||
USER_COUNT=$(node ./scripts/check-db.mjs)
|
|
||||||
|
|
||||||
if [ "$USER_COUNT" -eq "0" ]; then
|
|
||||||
echo "Database is empty, running seeds..."
|
|
||||||
pnpm db:seed
|
|
||||||
else
|
|
||||||
echo "Database already has data, skipping seeds..."
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Starting application..."
|
|
||||||
pnpm start
|
|
@@ -1,13 +1,14 @@
|
|||||||
services:
|
services:
|
||||||
palmr-api:
|
palmr:
|
||||||
image: kyantech/palmr-api:latest # Make sure to use the correct version (latest) of the image
|
image: kyantech/palmr:latest # Make sure to use the correct version (latest) of the image
|
||||||
container_name: palmr-api
|
container_name: palmr
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: "service_healthy"
|
condition: "service_healthy"
|
||||||
minio:
|
minio:
|
||||||
condition: "service_healthy"
|
condition: "service_healthy"
|
||||||
environment:
|
environment:
|
||||||
|
# Server environment variables
|
||||||
- PORT=${API_INTERNAL_PORT:-3333} # Port for the backend service
|
- PORT=${API_INTERNAL_PORT:-3333} # Port for the backend service
|
||||||
- DATABASE_URL=postgresql://postgres:${POSTGRESQL_PASSWORD:-postgresRootPassword}@postgres:5432/palmr_db?schema=public # Database URL with configurable password through POSTGRESQL_PASSWORD env var
|
- DATABASE_URL=postgresql://postgres:${POSTGRESQL_PASSWORD:-postgresRootPassword}@postgres:5432/palmr_db?schema=public # Database URL with configurable password through POSTGRESQL_PASSWORD env var
|
||||||
- MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio} # This can change if your MinIO is at a different address
|
- MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio} # This can change if your MinIO is at a different address
|
||||||
@@ -20,34 +21,21 @@ services:
|
|||||||
- FRONTEND_URL=${APP_URL:-http://${SERVER_IP:-localhost}:${APP_EXTERNAL_PORT:-5487}} # Frontend URL - Make sure to use the correct frontend URL, depends on where the frontend is running, its prepared for localhost, but you can change it to your frontend URL if needed
|
- FRONTEND_URL=${APP_URL:-http://${SERVER_IP:-localhost}:${APP_EXTERNAL_PORT:-5487}} # Frontend URL - Make sure to use the correct frontend URL, depends on where the frontend is running, its prepared for localhost, but you can change it to your frontend URL if needed
|
||||||
- SERVER_IP=${SERVER_IP:-localhost} # Server IP - Make sure to use the correct server IP if you running on a cloud provider or a virtual machine. This prepared for localhost, but you can change it to your server IP if needed
|
- SERVER_IP=${SERVER_IP:-localhost} # Server IP - Make sure to use the correct server IP if you running on a cloud provider or a virtual machine. This prepared for localhost, but you can change it to your server IP if needed
|
||||||
- MAX_FILESIZE=${MAX_FILESIZE:-1073741824} # Max Filesize for upload - Declared in Bytes. Default is 1GiB
|
- MAX_FILESIZE=${MAX_FILESIZE:-1073741824} # Max Filesize for upload - Declared in Bytes. Default is 1GiB
|
||||||
ports:
|
|
||||||
- "${API_EXTERNAL_PORT:-3333}:${API_INTERNAL_PORT:-3333}" # Backend port mapping
|
# Web environment variables
|
||||||
restart: unless-stopped
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "--no-verbose", "http://palmr-api:${API_INTERNAL_PORT:-3333}/health"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
start_period: 30s
|
|
||||||
|
|
||||||
palmr-app:
|
|
||||||
image: kyantech/palmr-app:latest # Make sure to use the correct version (latest) of the image
|
|
||||||
container_name: palmr-web
|
|
||||||
depends_on:
|
|
||||||
palmr-api:
|
|
||||||
condition: "service_healthy"
|
|
||||||
ports:
|
|
||||||
- "${APP_EXTERNAL_PORT:-5487}:5487" # Frontend port mapping
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=production
|
- NODE_ENV=production
|
||||||
- NEXT_TELEMETRY_DISABLED=1
|
- NEXT_TELEMETRY_DISABLED=1
|
||||||
- API_BASE_URL=http://palmr-api:${API_INTERNAL_PORT:-3333} # Here we use docker's internal network to reference the backend service (can be changed if needed)
|
- API_BASE_URL=http://palmr:${API_INTERNAL_PORT:-3333} # Using Docker service name for internal communication
|
||||||
|
ports:
|
||||||
|
- "${API_EXTERNAL_PORT:-3333}:3333" # Server port
|
||||||
|
- "${APP_EXTERNAL_PORT:-5487}:5487" # Web port
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:5487"]
|
test: ["CMD", "wget", "--no-verbose", "http://palmr:${API_INTERNAL_PORT:-3333}/health", "&&", "wget", "--no-verbose", "http://palmr:${APP_INTERNAL_PORT:-5487}"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
start_period: 60s
|
||||||
|
|
||||||
minio:
|
minio:
|
||||||
image: minio/minio:RELEASE.2025-03-12T18-04-18Z # Use only version RELEASE.2025-03-12T18-04-18Z to avoid compatibility issues with the backend
|
image: minio/minio:RELEASE.2025-03-12T18-04-18Z # Use only version RELEASE.2025-03-12T18-04-18Z to avoid compatibility issues with the backend
|
||||||
@@ -108,4 +96,4 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
minio_data:
|
minio_data:
|
||||||
postgres_data:
|
postgres_data:
|
33
infra/SCRIPTS.md
Normal file
33
infra/SCRIPTS.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
## 🚀 Quick Start
|
||||||
|
|
||||||
|
Palmr. includes a convenient Makefile to simplify development and deployment tasks:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Show all available commands
|
||||||
|
make help
|
||||||
|
|
||||||
|
# Build Docker image with multi-platform support
|
||||||
|
make build
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
make start
|
||||||
|
|
||||||
|
# View application logs
|
||||||
|
make logs
|
||||||
|
|
||||||
|
# Stop the application
|
||||||
|
make stop
|
||||||
|
|
||||||
|
# Clean up containers and images
|
||||||
|
make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Available Commands:
|
||||||
|
- `make build` - Build Docker image using the build script in `./infra/`
|
||||||
|
- `make start` - Start the application using docker-compose
|
||||||
|
- `make stop` - Stop all running containers
|
||||||
|
- `make logs` - Show application logs
|
||||||
|
- `make clean` - Clean up containers and images
|
||||||
|
- `make shell` - Access the application container shell
|
||||||
|
|
||||||
|
All infrastructure scripts are organized in the `./infra/` directory for better project organization.
|
43
infra/build-docker.sh
Executable file
43
infra/build-docker.sh
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Ask for tag interactively
|
||||||
|
echo "🏷️ Please enter a tag for the build (e.g., v1.0.0, production, beta):"
|
||||||
|
read -p "Tag: " TAG
|
||||||
|
|
||||||
|
# Check if tag was provided
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
|
echo "❌ Error: Tag cannot be empty"
|
||||||
|
echo "Please run the script again and provide a valid tag"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🚀 Building Palmr Unified Image for AMD64 and ARM..."
|
||||||
|
echo "📦 Building tags: latest and $TAG"
|
||||||
|
|
||||||
|
# Ensure buildx is available and create/use a builder instance
|
||||||
|
docker buildx create --name palmr-builder --use 2>/dev/null || docker buildx use palmr-builder
|
||||||
|
|
||||||
|
# Build the unified image for multiple platforms without cache
|
||||||
|
docker buildx build \
|
||||||
|
--platform linux/amd64,linux/arm64 \
|
||||||
|
--no-cache \
|
||||||
|
-t kyantech/palmr:latest \
|
||||||
|
-t kyantech/palmr:$TAG \
|
||||||
|
--load \
|
||||||
|
.
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "✅ Multi-platform build completed successfully!"
|
||||||
|
echo ""
|
||||||
|
echo "Built for platforms: linux/amd64, linux/arm64"
|
||||||
|
echo "Built tags: palmr:latest and palmr:$TAG"
|
||||||
|
echo ""
|
||||||
|
echo "Access points:"
|
||||||
|
echo "- API: http://localhost:3333"
|
||||||
|
echo "- Web App: http://localhost:5487"
|
||||||
|
echo ""
|
||||||
|
echo "Read the docs for more information"
|
||||||
|
else
|
||||||
|
echo "❌ Build failed!"
|
||||||
|
exit 1
|
||||||
|
fi
|
29
infra/server-start.sh
Normal file
29
infra/server-start.sh
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Starting Palmr Server..."
|
||||||
|
|
||||||
|
# Set proper environment
|
||||||
|
export HOME=/home/palmr
|
||||||
|
export NPM_CONFIG_CACHE=/home/palmr/.npm
|
||||||
|
export PNPM_HOME=/home/palmr/.pnpm
|
||||||
|
|
||||||
|
# Wait for PostgreSQL
|
||||||
|
echo "Waiting for PostgreSQL..."
|
||||||
|
while ! nc -z postgres 5432; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "PostgreSQL is up!"
|
||||||
|
|
||||||
|
cd /app/server
|
||||||
|
|
||||||
|
echo "Generating Prisma client..."
|
||||||
|
npx prisma generate --schema=./prisma/schema.prisma
|
||||||
|
|
||||||
|
echo "Running migrations..."
|
||||||
|
npx prisma migrate deploy
|
||||||
|
|
||||||
|
echo "Running database seeds..."
|
||||||
|
node prisma/seed.js || echo "Seeds failed or already exist, continuing..."
|
||||||
|
|
||||||
|
echo "Starting server application..."
|
||||||
|
exec node dist/server.js
|
Reference in New Issue
Block a user