initial commit
Some checks failed
Build Images and Deploy / Update-PROD-Stack (push) Failing after 17s

This commit is contained in:
2026-01-28 23:52:15 -05:00
commit 787c97a52f
13 changed files with 290 additions and 0 deletions

6
.env.example Normal file
View File

@@ -0,0 +1,6 @@
# Backend
PORT=4000
JWT_SECRET=your_jwt_secret
DATABASE_URL=postgres://postgres:postgres@db:5432/whats_the_point
# Frontend
VITE_API_URL=http://localhost:4000

View File

@@ -0,0 +1,76 @@
# https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions
name: Build Images and Deploy
run-name: ${{ gitea.actor }} is building new PROD images and redeploying the existing stack 🚀
on:
push:
# not working right now https://github.com/actions/runner/issues/2324
# paths-ignore:
# - **.yml
branches:
- main
env:
STACK_NAME: wtp-prod
DOT_ENV: ${{ secrets.PROD_ENV }}
PORTAINER_TOKEN: ${{ secrets.PORTAINER_TOKEN }}
PORTAINER_API_URL: https://portainer.dev.nervesocket.com/api
ENDPOINT_NAME: "mini" #sometimes "primary"
IMAGE_TAG: "reg.dev.nervesocket.com/wtp-prod:release"
jobs:
Update-PROD-Stack:
runs-on: ubuntu-latest
steps:
# if: contains(github.event.pull_request.head.ref, 'init-stack')
- name: Checkout
uses: actions/checkout@v4
with:
ref: main
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Build and push PROD Docker image
run: |
echo $DOT_ENV | base64 -d > .env
echo .env
docker buildx build --push -t $IMAGE_TAG .
- name: Get the endpoint ID
# Usually ID is 1, but you can get it from the API. Only skip this if you are VERY sure.
run: |
ENDPOINT_ID=$(curl -s -H "X-API-Key: $PORTAINER_TOKEN" "$PORTAINER_API_URL/endpoints" | jq -r ".[] | select(.Name==\"$ENDPOINT_NAME\") | .Id")
echo "ENDPOINT_ID=$ENDPOINT_ID" >> $GITHUB_ENV
echo "Got stack Endpoint ID: $ENDPOINT_ID"
- name: Fetch stack ID from Portainer
run: |
STACK_ID=$(curl -s -H "X-API-Key: $PORTAINER_TOKEN" "$PORTAINER_API_URL/stacks" | jq -r ".[] | select(.Name==\"$STACK_NAME\" and .EndpointId==$ENDPOINT_ID) | .Id")
echo "STACK_ID=$STACK_ID" >> $GITHUB_ENV
echo "Got stack ID: $STACK_ID matched with Endpoint ID: $ENDPOINT_ID"
- name: Redeploy stack in Portainer
run: |
# Read stack file content
STACK_FILE_CONTENT=$(echo "$(<prod-compose.yml )")
# Prepare JSON payload
JSON_PAYLOAD=$(jq -n --arg stackFileContent "$STACK_FILE_CONTENT" --argjson pullImage true \
'{stackFileContent: $stackFileContent, pullImage: $pullImage}')
echo "About to push the following JSON payload:"
echo $JSON_PAYLOAD
# Update stack in Portainer (this redeploys it)
DEPLOY_RESPONSE=$(curl -X PUT "$PORTAINER_API_URL/stacks/$STACK_ID?endpointId=$ENDPOINT_ID" \
-H "X-API-Key: $PORTAINER_TOKEN" \
-H "Content-Type: application/json" \
--data "$JSON_PAYLOAD")
echo "Redeployed stack in Portainer. Response:"
echo $DEPLOY_RESPONSE
- name: Status check
run: |
echo "📋 This job's status is ${{ job.status }}. Make sure you delete the init file to avoid issues."

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
# Node
node_modules/
.env
# Logs
logs
*.log
npm-debug.log*
# Build
build/
dist/
# OS
.DS_Store
Thumbs.db
# Vite
frontend/dist/

36
README.md Normal file
View File

@@ -0,0 +1,36 @@
# What's The Point
A web app for tracking predictions and points in TV/movie challenges with friends.
## Features
- Register/login with email and password
- Create and join challenges for shows/movies
- Make and approve predictions
- Mobile-first, modern UI
## Tech Stack
- Frontend: React (Vite)
- Backend: Node.js (Express)
- Database: PostgreSQL
- Auth: JWT (email/password)
- Dockerized, self-hosted
## Getting Started
### Prerequisites
- Docker & Docker Compose
### Setup
1. Copy `.env.example` to `.env` and fill in secrets.
2. Build and start all services:
```sh
docker compose up --build
```
3. Access the frontend at http://localhost:5173
4. API runs at http://localhost:4000
## Deployment
- See `prod-compose.yml` for production deployment.
## License
MIT

7
backend/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 4000
CMD ["npm", "run", "dev"]

17
backend/package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "wtp-backend",
"version": "0.1.0",
"main": "src/index.js",
"type": "module",
"scripts": {
"dev": "node src/index.js"
},
"dependencies": {
"express": "^4.18.2",
"pg": "^8.11.3",
"jsonwebtoken": "^9.0.2",
"bcryptjs": "^2.4.3",
"dotenv": "^16.4.5",
"cors": "^2.8.5"
}
}

17
backend/src/index.js Normal file
View File

@@ -0,0 +1,17 @@
import express from 'express';
import cors from 'cors';
import dotenv from 'dotenv';
dotenv.config();
const app = express();
app.use(cors());
app.use(express.json());
app.get('/', (req, res) => {
res.json({ message: "What's The Point API" });
});
const PORT = process.env.PORT || 4000;
app.listen(PORT, () => {
console.log(`API running on port ${PORT}`);
});

42
docker-compose.yml Normal file
View File

@@ -0,0 +1,42 @@
version: '3.8'
services:
db:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: whats_the_point
volumes:
- db_data:/var/lib/postgresql/data
ports:
- "5432:5432"
backend:
build: ./backend
restart: unless-stopped
environment:
PORT: 4000
JWT_SECRET: your_jwt_secret
DATABASE_URL: postgres://postgres:postgres@db:5432/whats_the_point
depends_on:
- db
ports:
- "4000:4000"
volumes:
- ./backend:/app
frontend:
build: ./frontend
restart: unless-stopped
environment:
VITE_API_URL: http://localhost:4000
depends_on:
- backend
ports:
- "5173:5173"
volumes:
- ./frontend:/app
volumes:
db_data:

7
frontend/Dockerfile Normal file
View File

@@ -0,0 +1,7 @@
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 5173
CMD ["npm", "run", "dev"]

12
frontend/index.html Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>What's The Point</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

17
frontend/package.json Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "wtp-frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"vite": "^5.0.0"
}
}

9
frontend/src/main.jsx Normal file
View File

@@ -0,0 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
const App = () => <div style={{fontFamily: 'sans-serif', padding: 24}}>
<h1>What's The Point</h1>
<p>Welcome! The app is running.</p>
</div>;
ReactDOM.createRoot(document.getElementById('root')).render(<App />);

29
prod-compose.yml Normal file
View File

@@ -0,0 +1,29 @@
services:
web:
image: reg.dev.nervesocket.com/wtp-prod:release
depends_on:
- db
restart: unless-stopped
environment:
- APACHE_LOG_DIR=/var/www/app
- TZ=America/Toronto
volumes:
- /volume1/docker/wtp-prod/production_web:/app/public/storage
ports:
- 22798:80
db:
# image: mariadb:10.7
image: linuxserver/mariadb
restart: unless-stopped
environment:
- MYSQL_ROOT_PASSWORD=XLxXDnUvfkTbDzDlEP5Gy8It
- TZ=America/Toronto
volumes:
- /volume1/docker/wtp-prod/db:/config
adminer:
image: adminer
restart: unless-stopped
ports:
- 22582:8080