ci(docker): add production dockerfile, compose config, and gitea actions pipeline
Build and Push Fridger Container / Build & Push Fridger Image (push) Failing after 31s
Build and Push Fridger Container / Build & Push Fridger Image (push) Failing after 31s
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
data
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
test.js
|
||||||
|
.gitea
|
||||||
|
*.md
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
name: Build and Push Fridger Container
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths-ignore:
|
||||||
|
- 'README.md'
|
||||||
|
- '.gitignore'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
name: Build & Push Fridger Image
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Ensure Docker CLI is available
|
||||||
|
run: |
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
echo "Docker CLI not found. Downloading static Docker CLI binary..."
|
||||||
|
curl -fSL --connect-timeout 15 --max-time 120 --retry 3 https://download.docker.com/linux/static/stable/x86_64/docker-27.3.1.tgz -o /tmp/docker.tgz
|
||||||
|
tar -xzf /tmp/docker.tgz -C /usr/local/bin --strip-components=1 docker/docker
|
||||||
|
chmod +x /usr/local/bin/docker
|
||||||
|
rm -f /tmp/docker.tgz
|
||||||
|
fi
|
||||||
|
docker version
|
||||||
|
|
||||||
|
- name: Log in to Gitea Container Registry
|
||||||
|
run: |
|
||||||
|
REGISTRY="gitea.eibl.tech"
|
||||||
|
USER="${{ secrets.GITEAUSER || secrets.PACKAGESUSER || github.actor }}"
|
||||||
|
PASS="${{ secrets.GITEATOKEN || secrets.PACKAGESTOKEN || secrets.TAG_TOKEN || github.token }}"
|
||||||
|
echo "Logging in to ${REGISTRY} as ${USER}..."
|
||||||
|
echo "${PASS}" | docker login "${REGISTRY}" -u "${USER}" --password-stdin
|
||||||
|
|
||||||
|
- name: Build Docker Image
|
||||||
|
env:
|
||||||
|
DOCKER_BUILDKIT: "0"
|
||||||
|
run: |
|
||||||
|
IMAGE_TAG="gitea.eibl.tech/me0nline/fridger:latest"
|
||||||
|
echo "Building ${IMAGE_TAG}..."
|
||||||
|
docker build \
|
||||||
|
-t "${IMAGE_TAG}" \
|
||||||
|
-f Dockerfile \
|
||||||
|
.
|
||||||
|
|
||||||
|
- name: Push to Gitea Container Registry
|
||||||
|
run: |
|
||||||
|
IMAGE_TAG="gitea.eibl.tech/me0nline/fridger:latest"
|
||||||
|
echo "Pushing ${IMAGE_TAG} to Gitea Container Registry..."
|
||||||
|
docker push "${IMAGE_TAG}"
|
||||||
|
echo "Successfully pushed ${IMAGE_TAG} to Gitea Container Registry!"
|
||||||
|
|
||||||
|
- name: Clean up temporary base images from Docker host
|
||||||
|
if: always()
|
||||||
|
run: |
|
||||||
|
echo "[*] Cleaning up temporary base images from Docker host daemon..."
|
||||||
|
docker images --filter "reference=*bullseye*" -q | xargs -r docker rmi -f 2>/dev/null || true
|
||||||
|
docker rmi -f node:16-bullseye node:16-bullseye-slim 2>/dev/null || true
|
||||||
|
docker image prune -f 2>/dev/null || true
|
||||||
|
echo "[+] Cleaned up intermediate build images from host daemon."
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
# Multi-stage lightweight Docker image for Fridger
|
||||||
|
FROM node:22-alpine AS runner
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Set environment
|
||||||
|
ENV NODE_ENV=production \
|
||||||
|
PORT=3000 \
|
||||||
|
FRIDGER_DATA_DIR=/data \
|
||||||
|
FRIDGER_DB_PATH=/data/fridger.db
|
||||||
|
|
||||||
|
# Install dependencies first for layer caching
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --omit=dev && npm cache clean --force
|
||||||
|
|
||||||
|
# Copy application source
|
||||||
|
COPY server.js db.js barcode.js ./
|
||||||
|
COPY public/ ./public/
|
||||||
|
|
||||||
|
# Setup persistent data storage directory with proper permissions
|
||||||
|
RUN mkdir -p /data && chown -R node:node /app /data
|
||||||
|
|
||||||
|
# Use non-root user
|
||||||
|
USER node
|
||||||
|
|
||||||
|
# Expose web port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Declare persistent volume
|
||||||
|
VOLUME ["/data"]
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||||
|
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
CMD ["node", "server.js"]
|
||||||
@@ -1,3 +1,100 @@
|
|||||||
# Fridger
|
# 🧊 Fridger
|
||||||
|
|
||||||
A docker web-app that is built to scan and store what you have in your fridge
|
> Smart Fridge Inventory & Grams Tracker with live Barcode Scanner and Dual View/Manage modes.
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
|
||||||
|
- **👁️ Fridge View Mode ("What's in my fridge?")**:
|
||||||
|
- Visual layout organized by shelf/compartment (Top Shelf, Middle Shelf, Bottom Shelf, Crisper Drawer, Door Rack, Freezer).
|
||||||
|
- Clear stock level and remaining grams/ml progress indicators with percentage fullness.
|
||||||
|
- Expiration countdown badges (Fresh, Expiring Soon, Expired).
|
||||||
|
- Quick consume buttons (`-50g`, `-100g`, `-1 item`, or custom slider).
|
||||||
|
|
||||||
|
- **⚙️ Manage Fridge Mode**:
|
||||||
|
- Full inventory CRUD management.
|
||||||
|
- **Dynamic Grams/Weight Tracking**: When an item has weight (e.g. 250g cheese pack, 1kg flour, 500ml cream), easily slide or click quick-adjustment chips (`-10g`, `-25g`, `-50g`, `-100g`, `Half`, `Empty`) to log partial usage after cooking.
|
||||||
|
- Opened vs. unopened item tracking with open date.
|
||||||
|
|
||||||
|
- **📸 Live Barcode Scanner & Search**:
|
||||||
|
- Camera-based barcode scanner (`html5-qrcode`) directly in your browser (mobile & desktop).
|
||||||
|
- Open Food Facts API integration for instant autofill: product title, brand, package net weight (grams/ml/units), category, and image.
|
||||||
|
- No nutrition/macro clutter — purely focused on what is in your fridge and how much is left!
|
||||||
|
|
||||||
|
- **🚀 Self-Contained Container & CI/CD**:
|
||||||
|
- Lightweight Alpine container (`node:22-alpine`) with built-in SQLite engine.
|
||||||
|
- Automated build & push pipeline via Gitea Actions to `gitea.eibl.tech/me0nline/fridger:latest`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐳 Quick Start with Docker
|
||||||
|
|
||||||
|
### Using Docker Run
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name fridger \
|
||||||
|
-p 3000:3000 \
|
||||||
|
-v fridger-data:/data \
|
||||||
|
gitea.eibl.tech/me0nline/fridger:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Docker Compose
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
fridger:
|
||||||
|
image: gitea.eibl.tech/me0nline/fridger:latest
|
||||||
|
container_name: fridger
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- fridger-data:/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
fridger-data:
|
||||||
|
name: fridger-data
|
||||||
|
```
|
||||||
|
|
||||||
|
Access the web interface at **`http://localhost:3000`**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠️ Local Development
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# 2. Run backend test suite
|
||||||
|
npm test
|
||||||
|
|
||||||
|
# 3. Start development server
|
||||||
|
npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📡 REST API Summary
|
||||||
|
|
||||||
|
| Method | Endpoint | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `GET` | `/api/items` | List items (supports `search`, `category`, `location`, `status`) |
|
||||||
|
| `GET` | `/api/items/:id` | Get single item details |
|
||||||
|
| `POST` | `/api/items` | Add item |
|
||||||
|
| `PUT` | `/api/items/:id` | Update item details |
|
||||||
|
| `PATCH` | `/api/items/:id/quantity` | Adjust grams/count (`{ delta: -50 }` or `{ newQuantity: 150 }`) |
|
||||||
|
| `DELETE` | `/api/items/:id` | Remove item |
|
||||||
|
| `GET` | `/api/barcode/:code` | Barcode lookup (local cache + Open Food Facts) |
|
||||||
|
| `GET` | `/api/stats` | Summary stats (total, fresh, expiring soon, opened, low) |
|
||||||
|
| `GET` | `/api/meta` | Predefined categories, shelf locations, and units |
|
||||||
|
| `GET` | `/health` | Healthcheck status |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📜 License
|
||||||
|
MIT
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
fridger:
|
||||||
|
image: gitea.eibl.tech/me0nline/fridger:latest
|
||||||
|
container_name: fridger
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- PORT=3000
|
||||||
|
- FRIDGER_DATA_DIR=/data
|
||||||
|
volumes:
|
||||||
|
- fridger-data:/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
fridger-data:
|
||||||
|
name: fridger-data
|
||||||
Reference in New Issue
Block a user