Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Dependencies
node_modules

# Build output
build
.svelte-kit

# Git
.git
.gitignore

# IDE
.vscode
.idea
*.swp
*.swo

# Logs
logs
*.log
npm-debug.log*

# OS files
.DS_Store
Thumbs.db

# Docker
Dockerfile
docker-compose*.yml
.dockerignore

# Documentation
README.md
LICENSE
*.md

# Development/Test
.env.local
.env.*.local
coverage
.nyc_output

# Config (mounted at runtime, not baked in)
# Keep config examples for build stage
!config/*.example.*
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Diadem Application
DIADEM_PORT=3900

# MariaDB Database (Diadem Internal)
MARIADB_ROOT_PASSWORD=changeme_root
MARIADB_DATABASE=diadem
MARIADB_USER=diadem
MARIADB_PASSWORD=changeme
55 changes: 55 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
FROM node:22-slim AS base
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app

FROM base AS deps

COPY package.json pnpm-lock.yaml ./
COPY patches ./patches/
RUN pnpm install --frozen-lockfile

FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN mkdir -p src/routes/\(custom\) && \
mkdir -p src/components/custom && \
mkdir -p src/lib/server && \
cp config/custom.example.css config/custom.css && \
cp config/Home.example.svelte config/Home.svelte && \
cp config/config.example.toml config/config.toml && \
ln config/custom.css src/custom.css && \
ln config/Home.svelte src/components/custom/Home.svelte && \
ln config/config.toml src/lib/server/config.toml
RUN pnpm run build

FROM node:22-slim AS runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
RUN groupadd --gid 1001 diadem && \
useradd --uid 1001 --gid diadem --shell /bin/bash --create-home diadem
COPY --from=builder --chown=diadem:diadem /app/build ./build
COPY --from=builder --chown=diadem:diadem /app/package.json ./
COPY --from=deps --chown=diadem:diadem /app/node_modules ./node_modules

# Files needed for drizzle-kit db:push at runtime
COPY --from=builder --chown=diadem:diadem /app/drizzle.config.ts ./
COPY --from=builder --chown=diadem:diadem /app/src/lib/server/db ./src/lib/server/db
COPY --from=builder --chown=diadem:diadem /app/src/lib/services ./src/lib/services

RUN mkdir -p /app/config /app/logs && chown diadem:diadem /app/config /app/logs
COPY --chown=diadem:diadem docker-entrypoint.sh ./
RUN chmod +x docker-entrypoint.sh
USER diadem
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=3900

EXPOSE 3900

HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD node -e "fetch('http://localhost:${PORT:-3900}').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"

ENTRYPOINT ["./docker-entrypoint.sh"]
111 changes: 111 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Diadem Docker Build & Release Makefile

# Registry and image configuration (override with environment variables)
DIADEM_DOCKER_REGISTRY ?= ghcr.io
DIADEM_DOCKER_REPOSITORY ?= ccev/diadem
DIADEM_DOCKER_IMAGE ?= $(DIADEM_DOCKER_REGISTRY)/$(DIADEM_DOCKER_REPOSITORY)

# Version tagging (defaults to git short hash)
GIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
GIT_DIRTY := $(shell git diff --quiet 2>/dev/null || echo "-dirty")
DIADEM_DOCKER_VERSION ?= $(GIT_HASH)$(GIT_DIRTY)

# Additional tags
DIADEM_DOCKER_LATEST_TAG ?= latest

# Docker build options
DIADEM_DOCKER_BUILD_ARGS ?=
DIADEM_DOCKER_PLATFORM ?= linux/amd64,linux/arm64
DIADEM_DOCKER_FILE ?= Dockerfile

# Helm chart
HELM_CHART_PATH := helm/diadem

.PHONY: help build release build-and-release tag clean lint helm-lint helm-package

help: ## Show this help message
@echo "Diadem Docker Build & Release"
@echo ""
@echo "Usage: make [target]"
@echo ""
@echo "Configuration (override with environment variables):"
@echo " DIADEM_DOCKER_REGISTRY = $(DIADEM_DOCKER_REGISTRY)"
@echo " DIADEM_DOCKER_REPOSITORY = $(DIADEM_DOCKER_REPOSITORY)"
@echo " DIADEM_DOCKER_IMAGE = $(DIADEM_DOCKER_IMAGE)"
@echo " DIADEM_DOCKER_VERSION = $(DIADEM_DOCKER_VERSION)"
@echo ""
@echo "Targets:"
@awk 'BEGIN {FS = ":.*##"; printf ""} /^[a-zA-Z_-]+:.*?##/ { printf " %-15s %s\n", $$1, $$2 }' $(MAKEFILE_LIST)

build: ## Build image for local platform only
docker build \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) \
--file $(DIADEM_DOCKER_FILE) \
$(DIADEM_DOCKER_BUILD_ARGS) \
.

release: ## Push locally built image to registry
docker push $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION)
docker push $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG)

build-and-release: ## Build multi-platform image and push to registry
docker buildx build \
--platform $(DIADEM_DOCKER_PLATFORM) \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) \
--tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) \
--file $(DIADEM_DOCKER_FILE) \
--push \
$(DIADEM_DOCKER_BUILD_ARGS) \
.

tag: ## Tag an existing image with a new tag (e.g., make tag NEW_TAG=v1.0.0)
@test -n "$(NEW_TAG)" || (echo "NEW_TAG is required" && exit 1)
docker buildx imagetools create \
--tag $(DIADEM_DOCKER_IMAGE):$(NEW_TAG) \
$(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION)

clean: ## Remove local images
-docker rmi $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) 2>/dev/null
-docker rmi $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) 2>/dev/null

lint: ## Lint Dockerfile with hadolint
@command -v hadolint >/dev/null 2>&1 && hadolint $(DIADEM_DOCKER_FILE) || \
docker run --rm -i hadolint/hadolint < $(DIADEM_DOCKER_FILE)

helm-lint: ## Lint Helm chart
helm lint $(HELM_CHART_PATH)

helm-package: ## Package Helm chart
helm package $(HELM_CHART_PATH)

helm-template: ## Render Helm chart templates
helm template diadem $(HELM_CHART_PATH)

# Docker Compose targets
.PHONY: up down logs

up: ## Start services with docker-compose
docker compose up -d

down: ## Stop services with docker-compose
docker compose down

logs: ## View docker-compose logs
docker compose logs -f

# Development helpers
.PHONY: setup-buildx info

setup-buildx: ## Set up Docker buildx for multi-platform builds
docker buildx create --name diadem-builder --use 2>/dev/null || docker buildx use diadem-builder
docker buildx inspect --bootstrap

info: ## Show build configuration
@echo "Registry: $(DIADEM_DOCKER_REGISTRY)"
@echo "Repository: $(DIADEM_DOCKER_REPOSITORY)"
@echo "Image: $(DIADEM_DOCKER_IMAGE)"
@echo "Version: $(DIADEM_DOCKER_VERSION)"
@echo "Git Hash: $(GIT_HASH)"
@echo "Platforms: $(DIADEM_DOCKER_PLATFORM)"
@echo "Dockerfile: $(DIADEM_DOCKER_FILE)"
3 changes: 3 additions & 0 deletions config/config.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
level = "info" #crit, error, warning, info, debug
# file = "/var/log/diadem.log"

[server.log.debug]
permissions = false # Enable verbose permission checking logs

[server.golbat]
url = "http://127.0.0.1:9001"
secret = ""
Expand Down
65 changes: 65 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
services:
diadem:
build:
context: .
dockerfile: Dockerfile
image: diadem:latest
container_name: diadem
restart: unless-stopped
ports:
- "${DIADEM_PORT:-3900}:3900"
environment:
- NODE_ENV=production
- HOST=0.0.0.0
- PORT=3900
volumes:
# Required: Mount your config file (both paths needed for runtime and db:push)
- ./config/config.toml:/app/build/server/config.toml:ro
- ./config/config.toml:/app/src/lib/server/config.toml:ro
# Optional: Persistent logs
- diadem-logs:/app/logs
depends_on:
diadem-db:
condition: service_healthy
networks:
- diadem-network
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3900').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s

diadem-db:
image: mariadb:11.4
container_name: diadem-db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:-changeme_root}
MARIADB_DATABASE: ${MARIADB_DATABASE:-diadem}
MARIADB_USER: ${MARIADB_USER:-diadem}
MARIADB_PASSWORD: ${MARIADB_PASSWORD:-changeme}
volumes:
- diadem-db-data:/var/lib/mysql
networks:
- diadem-network
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_unicode_ci

volumes:
diadem-db-data:
name: diadem-db-data
diadem-logs:
name: diadem-logs

networks:
diadem-network:
name: diadem-network
driver: bridge
17 changes: 17 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
set -e

# Only run db:push if the database appears to be uninitialized
# This prevents accidental destructive schema changes in production
if [ "${SKIP_DB_PUSH:-}" = "true" ]; then
echo "Skipping database push (SKIP_DB_PUSH=true)"
elif [ "${FORCE_DB_PUSH:-}" = "true" ]; then
echo "Running database push (forced)..."
npx drizzle-kit push --force
else
echo "Running database push..."
npx drizzle-kit push
fi

echo "Starting Diadem..."
exec node build/index.js
15 changes: 15 additions & 0 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ import type { User } from "@/lib/server/db/internal/schema";
import { DISCORD_REFRESH_INTERVAL, PERMISSION_UPDATE_INTERVAL } from "@/lib/constants";
import { getDiscordAuth } from "@/lib/server/auth/discord";
import type { Perms } from "@/lib/utils/features";
import { getLogger } from "@/lib/server/logging";
import { setServerLoggerFactory } from "@/lib/utils/logger";
import { getServerConfig } from "@/lib/services/config/config.server";

// Inject winston logger into universal logger for server-side use
const logConfig = getServerConfig().log;
setServerLoggerFactory((name) => {
const winstonLogger = getLogger(name);
return {
debug: (message, ...args) => winstonLogger.debug(message, ...args),
info: (message, ...args) => winstonLogger.info(message, ...args),
warning: (message, ...args) => winstonLogger.warning(message, ...args),
error: (message, ...args) => winstonLogger.error(message, ...args),
};
}, logConfig.debug);

const permissionCache: TTLCache<string, undefined> = new TTLCache({
ttl: PERMISSION_UPDATE_INTERVAL * 1000
Expand Down
5 changes: 5 additions & 0 deletions src/lib/services/config/configTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,14 @@ export type Permissions = {
features?: FeaturesKey[]
}

export type Debug = {
permissions?: boolean
}

export type Log = {
level: string
file?: string
debug?: Debug
}

export type MapStyle = {
Expand Down
Loading