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
64 changes: 64 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Dependencies
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Next.js
.next
out
build
dist

# Testing
coverage
.nyc_output

# Misc
.DS_Store
*.pem
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Debug
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Docker
Dockerfile
*.Dockerfile
.dockerignore
docker-compose.yml
compose.yaml
!docker-entrypoint.sh

# Git
.git
.gitignore
.gitattributes

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

# Documentation
README.md
CHANGELOG.md
LICENSE

# CI/CD
.github
.gitlab-ci.yml

# Database
*.db
*.sqlite
data/
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Database Configuration
DATABASE_URL=postgresql://lexhub:lexhub_password@localhost:5432/lexhub

# Next.js Configuration
NODE_ENV=development
PORT=10000

# Nexus Configuration (if needed for local development)
NEXUS_URL=http://localhost:8080
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ yarn-error.log*

# env files (can opt-in for committing if needed)
.env*
!.env.example

# vercel
.vercel
Expand Down
45 changes: 21 additions & 24 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,61 +1,58 @@
# Build stage
FROM node:20-alpine AS builder

# Install dependencies needed for build
RUN apk add --no-cache libc6-compat

WORKDIR /app

# Copy package files
COPY package.json package-lock.json* ./

# Install dependencies
RUN apk add --no-cache libc6-compat
COPY package.json package-lock.json* ./
RUN npm ci

# Copy source code
# Copy source and build
COPY . .

# Set environment to production
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

# Build the application
RUN npm run build

# Production stage
# Runtime stage
FROM node:20-alpine AS runner

WORKDIR /app

# Install runtime dependencies
RUN apk add --no-cache curl
RUN apk add --no-cache curl postgresql-client

# Create a non-root user
# Create non-root user
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs

# Copy necessary files from builder
COPY --from=builder /app/public ./public
# Copy standalone output and static files
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

# Copy migration files and dependencies for drizzle-kit
COPY --from=builder /app/drizzle ./drizzle
COPY --from=builder /app/drizzle.config.ts ./drizzle.config.ts
COPY --from=builder /app/src/db ./src/db
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

# Copy entrypoint script
COPY --from=builder /app/docker-entrypoint.sh ./docker-entrypoint.sh
RUN chmod +x ./docker-entrypoint.sh

# Set ownership to nextjs user
# Set ownership
RUN chown -R nextjs:nodejs /app

# Switch to non-root user
USER nextjs

# Expose the port the app runs on
EXPOSE 10000

# Set environment variables
ENV NODE_ENV=production
ENV PORT=10000
ENV HOSTNAME="0.0.0.0"

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:10000/ || exit 1

# Start the application
CMD ["node", "server.js"]
ENTRYPOINT ["/app/docker-entrypoint.sh"]
56 changes: 53 additions & 3 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@ services:
container_name: lexhub
restart: unless-stopped
depends_on:
- nexus
postgres:
condition: service_healthy
nexus:
condition: service_started
ports:
- "10000:10000"
environment:
- NODE_ENV=production
- NEXUS_URL=http://nexus:8080
- DATABASE_URL=postgresql://lexhub:lexhub_password@postgres:5432/lexhub
- POSTGRES_HOST=postgres
- POSTGRES_PORT=5432
- POSTGRES_USER=lexhub
- POSTGRES_PASSWORD=lexhub_password
- POSTGRES_DB=lexhub

nexus:
build:
Expand All @@ -21,8 +30,8 @@ services:
restart: unless-stopped
ports:
- "8080:8080"
# volumes:
# - ./data:/app/data
volumes:
- nexus_data:/app/data
environment:
# Relay configuration
- NEXUS_RELAY_URL=https://relay1.us-east.bsky.network
Expand All @@ -48,3 +57,44 @@ services:

# Logging
- NEXUS_LOG_LEVEL=info

postgres:
image: postgres:17-alpine

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Do we want to use 18 which is the current version and has some performance improvement?

In subsequent versions of postgres the mount directory is changed to: /var/lib/postgresql, https://github.com/docker-library/docs/blob/master/postgres/README.md#pgdata, potentially save some debugging down the line should people upgrade the db version.

container_name: postgres
restart: unless-stopped
ports:
- "5432:5432"
environment:
- POSTGRES_USER=lexhub
- POSTGRES_PASSWORD=lexhub_password
- POSTGRES_DB=lexhub
- PGDATA=/var/lib/postgresql/data/pgdata
volumes:
- postgres_data:/var/lib/postgresql/data
command:
- "postgres"
- "-c"
- "shared_preload_libraries=pg_stat_statements"
- "-c"
- "pg_stat_statements.track=all"
- "-c"
- "max_connections=200"
- "-c"
- "shared_buffers=256MB"
- "-c"
- "effective_cache_size=1GB"
- "-c"
- "work_mem=16MB"
- "-c"
- "maintenance_work_mem=128MB"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U lexhub -d lexhub"]
interval: 10s
timeout: 5s
retries: 5

volumes:
nexus_data:
driver: local
postgres_data:
driver: local
19 changes: 19 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env sh
set -e

echo "Starting LexHub application..."

# Wait for PostgreSQL to be ready
echo "Waiting for PostgreSQL to be ready..."
until pg_isready -h "$POSTGRES_HOST" -p "$POSTGRES_PORT" -U "$POSTGRES_USER"; do
echo "PostgreSQL is unavailable - sleeping"
sleep 2
done
echo "PostgreSQL is ready!"

# Run database migrations
echo "Running database migrations..."
npm run db:migrate

# Start the Next.js application
exec node server.js
12 changes: 12 additions & 0 deletions drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineConfig } from "drizzle-kit";

export default defineConfig({
dialect: "postgresql",
schema: "./src/db/schema.ts",
out: "./drizzle",
dbCredentials: {
url:
process.env.DATABASE_URL ||
"postgresql://lexhub:lexhub_password@localhost:5432/lexhub",
},
});
26 changes: 26 additions & 0 deletions drizzle/0000_init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
CREATE TABLE "lexicons" (
"id" varchar(317) NOT NULL,
"cid" varchar(100) NOT NULL,
"data" jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "lexicons_id_cid_pk" PRIMARY KEY("id","cid")
);
--> statement-breakpoint
CREATE INDEX "lexicons_id_idx" ON "lexicons" USING btree ("id");--> statement-breakpoint
CREATE INDEX "lexicons_created_at_idx" ON "lexicons" USING btree ("created_at");--> statement-breakpoint
CREATE INDEX "lexicons_data_gin_idx" ON "lexicons" USING gin ("data");--> statement-breakpoint


CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ language 'plpgsql';

CREATE TRIGGER update_lexicons_updated_at
BEFORE UPDATE ON "lexicons"
FOR EACH ROW
EXECUTE FUNCTION update_updated_at_column();
Loading