mirror of
https://github.com/kyantech/Palmr.git
synced 2025-11-02 13:03:15 +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
|
||||
services:
|
||||
palmr-api:
|
||||
image: kyantech/palmr-api:latest # Make sure to use the correct version (latest) of the image
|
||||
container_name: palmr-api
|
||||
palmr:
|
||||
image: kyantech/palmr:latest # Make sure to use the correct version (latest) of the image
|
||||
container_name: palmr
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: "service_healthy"
|
||||
minio:
|
||||
condition: "service_healthy"
|
||||
environment:
|
||||
# Server environment variables
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
ports:
|
||||
- "${API_EXTERNAL_PORT:-3333}:${API_INTERNAL_PORT:-3333}" # Backend port mapping
|
||||
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:
|
||||
|
||||
# Web environment variables
|
||||
- NODE_ENV=production
|
||||
- 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
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:5487"]
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3333/health", "&&", "curl", "-f", "http://localhost:5487"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
|
||||
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
|
||||
@@ -138,7 +126,7 @@ services:
|
||||
|
||||
volumes:
|
||||
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
|
||||
|
||||
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** |
|
||||
| --- | --- | --- | --- |
|
||||
| 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-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 |
|
||||
| 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 |
|
||||
| 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 |
|
||||
| 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:
|
||||
|
||||
```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):
|
||||
|
||||
- **Frontend:** [http://localhost:5487](http://localhost:5487)
|
||||
- **Backend:** [http://localhost:3333](http://localhost:3333/)
|
||||
- **MinIO API:** [http://localhost:6421](http://localhost:6421)
|
||||
- **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.*
|
||||
>
|
||||
@@ -247,7 +238,7 @@ If you haven't changed the execution ports, you'll have access on your server at
|
||||
- **Backend:** `[server_ip]:3333`
|
||||
- **MinIO API:** `[server_ip]:6421`
|
||||
- **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.*
|
||||
>
|
||||
|
||||
@@ -25,4 +25,4 @@
|
||||
"gh-sponsor",
|
||||
"..."
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,12 @@ export default function HomePage() {
|
||||
function Hero() {
|
||||
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">
|
||||
<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">
|
||||
Modern & efficient file sharing
|
||||
</h1>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { source } from '@/lib/source';
|
||||
import { createFromSource } from 'fumadocs-core/search/server';
|
||||
|
||||
import { source } from "@/lib/source";
|
||||
import { createFromSource } from "fumadocs-core/search/server";
|
||||
|
||||
export const { GET } = createFromSource(source, (page) => {
|
||||
return {
|
||||
title: page.data.title,
|
||||
@@ -8,6 +8,8 @@ export const { GET } = createFromSource(source, (page) => {
|
||||
url: page.url,
|
||||
id: page.url,
|
||||
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 = {
|
||||
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 }) {
|
||||
return (
|
||||
<html lang="en" className={inter.className} suppressHydrationWarning>
|
||||
<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>
|
||||
</Banner>
|
||||
<RootProvider
|
||||
|
||||
@@ -11,7 +11,10 @@
|
||||
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
|
||||
"format": "prettier . --write",
|
||||
"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": [],
|
||||
"author": "",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { prisma } from "../src/shared/prisma";
|
||||
import crypto from "node:crypto";
|
||||
import { env } from '../src/env';
|
||||
/* eslint-disable no-undef */
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const defaultConfigs = [
|
||||
// General Configurations
|
||||
@@ -37,7 +39,7 @@ const defaultConfigs = [
|
||||
// Storage Configurations
|
||||
{
|
||||
key: "maxFileSize",
|
||||
value: env.MAX_FILESIZE, // default 1GiB in bytes - 1073741824
|
||||
value: process.env.MAX_FILESIZE || "1073741824", // default 1GiB in bytes
|
||||
type: "bigint",
|
||||
group: "storage",
|
||||
},
|
||||
@@ -124,28 +126,37 @@ const defaultConfigs = [
|
||||
];
|
||||
|
||||
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) {
|
||||
if (config.key === "jwtSecret") {
|
||||
const existingSecret = await prisma.appConfig.findUnique({
|
||||
where: { key: "jwtSecret" },
|
||||
});
|
||||
// Check if configuration already exists
|
||||
const existingConfig = await prisma.appConfig.findUnique({
|
||||
where: { key: config.key },
|
||||
});
|
||||
|
||||
if (existingSecret) {
|
||||
console.log("JWT secret already exists, skipping...");
|
||||
continue;
|
||||
}
|
||||
if (existingConfig) {
|
||||
console.log(`⏭️ Configuration '${config.key}' already exists, skipping...`);
|
||||
skippedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
await prisma.appConfig.upsert({
|
||||
where: { key: config.key },
|
||||
update: config,
|
||||
create: config,
|
||||
// Only create if it doesn't exist
|
||||
await prisma.appConfig.create({
|
||||
data: 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()
|
||||
@@ -155,4 +166,4 @@ main()
|
||||
})
|
||||
.finally(async () => {
|
||||
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:
|
||||
palmr-api:
|
||||
image: kyantech/palmr-api:latest # Make sure to use the correct version (latest) of the image
|
||||
container_name: palmr-api
|
||||
palmr:
|
||||
image: kyantech/palmr:latest # Make sure to use the correct version (latest) of the image
|
||||
container_name: palmr
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: "service_healthy"
|
||||
minio:
|
||||
condition: "service_healthy"
|
||||
environment:
|
||||
# Server environment variables
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
ports:
|
||||
- "${API_EXTERNAL_PORT:-3333}:${API_INTERNAL_PORT:-3333}" # Backend port mapping
|
||||
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:
|
||||
|
||||
# Web environment variables
|
||||
- NODE_ENV=production
|
||||
- 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
|
||||
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
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
|
||||
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
|
||||
@@ -108,4 +96,4 @@ services:
|
||||
|
||||
volumes:
|
||||
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