mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a815c92e6 | ||
|
|
cef9b5c8fc | ||
|
|
1e2476a375 | ||
|
|
78b762bd9e |
@@ -1,7 +1,47 @@
|
|||||||
|
# Dependencies (will be installed fresh in container)
|
||||||
node_modules/
|
node_modules/
|
||||||
npm-debug.log
|
|
||||||
test/
|
# Database and config (mounted as volumes)
|
||||||
db/
|
db/
|
||||||
conf/
|
conf/
|
||||||
|
|
||||||
|
# Git
|
||||||
.git/
|
.git/
|
||||||
.github/
|
.github/
|
||||||
|
.gitignore
|
||||||
|
|
||||||
|
# IDE and editor
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
test/
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
doc/
|
||||||
|
*.md
|
||||||
|
!README.md
|
||||||
|
|
||||||
|
# Development config files
|
||||||
|
.babelrc
|
||||||
|
.husky/
|
||||||
|
.nvmrc
|
||||||
|
.prettierrc
|
||||||
|
.prettierignore
|
||||||
|
eslint.config.js
|
||||||
|
|
||||||
|
# Docker files (not needed inside container)
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.yml
|
||||||
|
docker-test.sh
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log
|
||||||
|
|
||||||
|
# Build artifacts (built fresh in container)
|
||||||
|
dist/
|
||||||
|
|||||||
66
Dockerfile
66
Dockerfile
@@ -1,27 +1,58 @@
|
|||||||
FROM node:22-slim
|
# ================================
|
||||||
|
# Stage 1: Build stage
|
||||||
|
# ================================
|
||||||
|
FROM node:22-alpine AS builder
|
||||||
|
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Install build dependencies needed for native modules (better-sqlite3)
|
||||||
|
RUN apk add --no-cache python3 make g++
|
||||||
|
|
||||||
|
# Copy package files first for better layer caching
|
||||||
|
COPY package.json yarn.lock ./
|
||||||
|
|
||||||
|
# Install all dependencies (including devDependencies for building)
|
||||||
|
RUN yarn config set network-timeout 600000 \
|
||||||
|
&& yarn --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source files needed for build
|
||||||
|
COPY index.html vite.config.js ./
|
||||||
|
COPY ui ./ui
|
||||||
|
COPY lib ./lib
|
||||||
|
|
||||||
|
# Build frontend assets
|
||||||
|
RUN yarn build:frontend
|
||||||
|
|
||||||
|
# ================================
|
||||||
|
# Stage 2: Production stage
|
||||||
|
# ================================
|
||||||
|
FROM node:22-alpine
|
||||||
|
|
||||||
WORKDIR /fredy
|
WORKDIR /fredy
|
||||||
|
|
||||||
# Install Chromium and curl without extra recommended packages and clean apt cache
|
# Install Chromium and curl (for healthcheck)
|
||||||
# curl is needed for the health check
|
# Using Alpine's chromium package which is much smaller
|
||||||
RUN apt-get update \
|
RUN apk add --no-cache chromium curl
|
||||||
&& apt-get install -y --no-install-recommends chromium curl \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
|
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
|
||||||
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
|
PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser
|
||||||
|
|
||||||
# Copy lockfiles first to leverage cache for dependencies
|
# Install build dependencies for native modules, then remove them after yarn install
|
||||||
COPY package.json yarn.lock .
|
COPY package.json yarn.lock ./
|
||||||
|
|
||||||
# Set Yarn timeout, install dependencies and PM2 globally
|
RUN apk add --no-cache --virtual .build-deps python3 make g++ \
|
||||||
RUN yarn config set network-timeout 600000 \
|
&& yarn config set network-timeout 600000 \
|
||||||
&& yarn --frozen-lockfile \
|
&& yarn --frozen-lockfile --production \
|
||||||
&& yarn global add pm2
|
&& yarn cache clean \
|
||||||
|
&& apk del .build-deps
|
||||||
|
|
||||||
# Copy application source and build production assets
|
# Copy built frontend from builder stage
|
||||||
COPY . .
|
COPY --from=builder /build/ui/public ./ui/public
|
||||||
RUN yarn build:frontend
|
|
||||||
|
# Copy application source (only what's needed at runtime)
|
||||||
|
COPY index.js ./
|
||||||
|
COPY index.html ./
|
||||||
|
COPY lib ./lib
|
||||||
|
|
||||||
# Prepare runtime directories and symlinks for data and config
|
# Prepare runtime directories and symlinks for data and config
|
||||||
RUN mkdir -p /db /conf \
|
RUN mkdir -p /db /conf \
|
||||||
@@ -34,5 +65,4 @@ EXPOSE 9998
|
|||||||
VOLUME /db
|
VOLUME /db
|
||||||
VOLUME /conf
|
VOLUME /conf
|
||||||
|
|
||||||
# Start application using PM2 runtime
|
CMD ["node", "index.js"]
|
||||||
CMD ["pm2-runtime", "index.js"]
|
|
||||||
|
|||||||
@@ -107,6 +107,10 @@ yarn run start:frontend # in another terminal
|
|||||||
|
|
||||||
👉 Open <http://localhost:9998>
|
👉 Open <http://localhost:9998>
|
||||||
|
|
||||||
|
### With Unraid
|
||||||
|
|
||||||
|
Should you use [Unraid](https://unraid.net/), you can now install Fredy from the community store :)
|
||||||
|
|
||||||
**Default Login:**
|
**Default Login:**
|
||||||
- Username: `admin`
|
- Username: `admin`
|
||||||
- Password: `admin`
|
- Password: `admin`
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
services:
|
services:
|
||||||
fredy:
|
fredy:
|
||||||
container_name: fredy
|
container_name: fredy
|
||||||
# build from empty build folder to reduce size of image
|
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: ghcr.io/orangecoding/fredy
|
image: ghcr.io/orangecoding/fredy
|
||||||
# map existing config and database
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./conf:/conf
|
- ./conf:/conf
|
||||||
- ./db:/db
|
- ./db:/db
|
||||||
ports:
|
ports:
|
||||||
- "9998:9998"
|
- "9998:9998"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
# Resource limits to prevent runaway memory usage from Chromium
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 1G
|
||||||
healthcheck:
|
healthcheck:
|
||||||
# The container will immediately stop when health check fails after retries
|
test: ["CMD", "curl", "--fail", "--silent", "--show-error", "--max-time", "5", "http://localhost:9998/"]
|
||||||
test: ["CMD-SHELL", "curl --fail --silent --show-error --max-time 5 http://localhost:9998/ || exit 1"]
|
|
||||||
interval: 120s
|
interval: 120s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 1
|
retries: 3
|
||||||
start_period: 10s
|
start_period: 30s
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
export const DEFAULT_CONFIG = {
|
export const DEFAULT_CONFIG = {
|
||||||
interval: '60',
|
|
||||||
port: 9998,
|
|
||||||
workingHours: { from: '', to: '' },
|
|
||||||
demoMode: false,
|
|
||||||
analyticsEnabled: null,
|
|
||||||
// Default path for sqlite storage directory. Interpreted relative to project root.
|
// Default path for sqlite storage directory. Interpreted relative to project root.
|
||||||
sqlitepath: '/db',
|
sqlitepath: '/db',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import fs from 'fs';
|
|||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import logger from '../../../logger.js';
|
import logger from '../../../logger.js';
|
||||||
|
import { DEFAULT_CONFIG } from '../../../../defaultConfig.js';
|
||||||
|
import { getDirName } from '../../../../utils.js';
|
||||||
|
|
||||||
export function up(db) {
|
export function up(db) {
|
||||||
db.exec(`
|
db.exec(`
|
||||||
@@ -67,6 +69,10 @@ export function up(db) {
|
|||||||
'analyticsEnabled',
|
'analyticsEnabled',
|
||||||
config.analyticsEnabled != null ? config.analyticsEnabled : defaults.analyticsEnabled,
|
config.analyticsEnabled != null ? config.analyticsEnabled : defaults.analyticsEnabled,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//now making sure only sqlite path remains in the config
|
||||||
|
const sqlitepath = config.sqlitepath || DEFAULT_CONFIG.sqlitepath;
|
||||||
|
fs.writeFileSync(`${getDirName()}/../conf/config.json`, JSON.stringify({ sqlitepath }));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e);
|
logger.error(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ function compileSettings(rows, configValues) {
|
|||||||
config[r.name] = parsed && typeof parsed === 'object' && 'value' in parsed ? parsed.value : parsed;
|
config[r.name] = parsed && typeof parsed === 'object' && 'value' in parsed ? parsed.value : parsed;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
...config,
|
|
||||||
...configValues,
|
...configValues,
|
||||||
|
...config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fredy",
|
"name": "fredy",
|
||||||
"version": "15.0.0",
|
"version": "15.1.1",
|
||||||
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
|
"description": "[F]ind [R]eal [E]states [d]amn eas[y].",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
|
|||||||
Reference in New Issue
Block a user