initial commit
Some checks failed
Build Images and Deploy / Update-PROD-Stack (push) Failing after 17s
Some checks failed
Build Images and Deploy / Update-PROD-Stack (push) Failing after 17s
This commit is contained in:
6
.env.example
Normal file
6
.env.example
Normal 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
|
||||||
76
.gitea/workflows/rebuild-prod.yaml
Normal file
76
.gitea/workflows/rebuild-prod.yaml
Normal 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
15
.gitignore
vendored
Normal 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
36
README.md
Normal 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
7
backend/Dockerfile
Normal 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
17
backend/package.json
Normal 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
17
backend/src/index.js
Normal 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
42
docker-compose.yml
Normal 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
7
frontend/Dockerfile
Normal 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
12
frontend/index.html
Normal 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
17
frontend/package.json
Normal 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
9
frontend/src/main.jsx
Normal 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
29
prod-compose.yml
Normal 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
|
||||||
Reference in New Issue
Block a user