Working base server with migrations and build steps ironed out (#1)

Reviewed-on: #1
Co-authored-by: Joseph Nelson <joseph.nelson4456@gmail.com>
Co-committed-by: Joseph Nelson <joseph.nelson4456@gmail.com>
This commit was merged in pull request #1.
This commit is contained in:
2026-05-13 23:16:20 -07:00
committed by joseph.nelson4456
parent 12922c35bf
commit ce914f91fd
16 changed files with 323 additions and 0 deletions
+20
View File
@@ -0,0 +1,20 @@
#!/bin/bash
# Check if the lint fix command fails
# If it does, exit with a non-zero status to prevent the commit.
echo "Running lint fix..."
# Replace with your actual lint fix command
# This is just an example, adapt it to your linter and project
npm run lint:fix # e.g., "eslint . --fix"
# Example: Capture the exit code of the command
lint_fix_result=$?
if [ $lint_fix_result -ne 0 ]; then
echo "Linting failed. Commit aborted."
exit 1 # Exit with a non-zero status to prevent the commit
fi
echo "Lint fix completed successfully. Commit allowed."
exit 0 # Exit with a zero status to allow the commit
+39
View File
@@ -0,0 +1,39 @@
name: Build and Push Image
on:
pull_request:
branches:
- main
types: [closed]
jobs:
build-and-push:
if: gitea.event.pull_request.merged == true
runs-on: ubuntu-latest
container:
image: catthehacker/ubuntu:act-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Log in to Gitea Registry
uses: docker/login-action@v2
with:
registry: gitea.nelson-household.com # Replace with your Gitea domain
username: ${{ gitea.actor }}
password: ${{ secrets.RUNNER_TOKEN }}
- name: Delete Old Images and Containers
run: |
docker ps -a -q -f "name=tcg-collectors-server" | xargs -I {} docker rm {} || true
docker images --format "{{.Repository}}:{{.Tag}}" | grep "tcg-collectors-server" | xargs -I {} docker rmi {} || true
- name: Build and Push Image
run: |
docker build \
--build-arg DATABASE_URL=${{ secrets.DATABASE_URL }} \
-t gitea.nelson-household.com/hard-at-work/tcg-collectors-server/tcg-collectors-server:${{ github.sha }} .
docker push gitea.nelson-household.com/hard-at-work/tcg-collectors-server/tcg-collectors-server:${{ github.sha }}
- name: Execute Migrations
run: |
docker run gitea.nelson-household.com/hard-at-work/tcg-collectors-server/tcg-collectors-server:${{ github.sha }} npm run migrate up
+2
View File
@@ -0,0 +1,2 @@
node_modules
package-lock.json
+11
View File
@@ -0,0 +1,11 @@
FROM node:24-alpine
ARG DATABASE_URL
ENV DATABASE_URL=${DATABASE_URL}
WORKDIR /app
COPY . .
RUN npm install --force
CMD ["npm", "run", "start"]
+30
View File
@@ -0,0 +1,30 @@
const express = require('express')
const path = require('path')
const authRoutes = require('./routes/auth')
const productsRoutes = require('./routes/products')
const usersRoutes = require('./routes/users')
const app = express()
const port = process.env.PORT || 3000
// Middleware
app.use(express.json()) // For parsing application/json
app.use(express.urlencoded({ extended: true })) // For parsing URL-encoded form data
// Static Files (Serving Frontend)
app.use(express.static(path.join(__dirname, 'public')))
// Mount Routes
app.use('/auth', authRoutes)
app.use('/products', productsRoutes)
app.use('/users', usersRoutes)
// Default Route (Catch-all for undefined routes)
app.use((req, res, next) => {
res.status(404).send('Sorry, the resource you requested could not be found.')
})
app.listen(port, () => {
console.log(`Server listening on port ${port}`)
})
+10
View File
@@ -0,0 +1,10 @@
// config/index.js
export default {
database: {
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'your_db_user',
password: process.env.DB_PASSWORD || 'your_db_password',
database: process.env.DB_NAME || 'your_db_name',
port: process.env.DB_PORT || 5432,
},
}
+27
View File
@@ -0,0 +1,27 @@
// eslint.config.js (Advanced alternative)
import prettierPlugin from 'eslint-plugin-prettier'
import prettierConfig from 'eslint-config-prettier'
import prettierOptions from './prettier.config.js' // Import your config directly
import importPlugin from 'eslint-plugin-import'
export default [
{
plugins: {
prettier: prettierPlugin,
import: importPlugin,
},
rules: {
...prettierConfig.rules,
'prettier/prettier': ['error', prettierOptions],
'no-sequences': 'off',
'no-console': 'warn',
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
'import/no-unresolved': 'error',
'import/no-unused-modules': ['warn', { missingExports: true }],
quotes: ['error', 'single'],
semi: 'off',
},
},
]
+17
View File
@@ -0,0 +1,17 @@
export const up = (pgm) => {
pgm.sql(`
CREATE TABLE images (
id UUID PRIMARY KEY,
file TEXT,
image BYTEA,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
`)
}
export const down = (pgm) => {
pgm.sql(`
DROP TABLE images;
`)
}
+18
View File
@@ -0,0 +1,18 @@
export const up = (pgm) => {
pgm.sql(`
CREATE TABLE collections (
id UUID PRIMARY KEY,
name TEXT,
image_id UUID,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
FOREIGN KEY (image_id) REFERENCES images(id)
);
`)
}
export const down = (pgm) => {
pgm.sql(`
DROP TABLE collections;
`)
}
+25
View File
@@ -0,0 +1,25 @@
export const up = (pgm) => {
pgm.sql(`
CREATE TABLE items (
id UUID PRIMARY KEY,
collection_id UUID,
image_id UUID,
productId TEXT,
name TEXT,
cleanName TEXT,
extCardText TEXT,
marketPrice TEXT,
extRarity TEXT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
FOREIGN KEY (collection_id) REFERENCES collections(id),
FOREIGN KEY (image_id) REFERENCES images(id)
);
`)
}
export const down = (pgm) => {
pgm.sql(`
DROP TABLE items;
`)
}
+16
View File
@@ -0,0 +1,16 @@
export const up = (pgm) => {
pgm.sql(`
CREATE TABLE locations (
id UUID PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
`)
}
export const down = (pgm) => {
pgm.sql(`
DROP TABLE locations;
`)
}
+22
View File
@@ -0,0 +1,22 @@
export const up = (pgm) => {
pgm.sql(`
CREATE TABLE sets (
id UUID PRIMARY KEY,
collection_id UUID NOT NULL,
name TEXT NOT NULL,
location_id UUID,
image_id UUID,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
FOREIGN KEY (collection_id) REFERENCES collections(id),
FOREIGN KEY (location_id) REFERENCES locations(id),
FOREIGN KEY (image_id) REFERENCES images(id)
);
`)
}
export const down = (pgm) => {
pgm.sql(`
DROP TABLE sets;
`)
}
+16
View File
@@ -0,0 +1,16 @@
export const up = (pgm) => {
pgm.sql(`
CREATE TABLE roles (
id UUID PRIMARY KEY,
name TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
`)
}
export const down = (pmg) => {
pgm.sql(`
DROP TABLE roles;
`)
}
+20
View File
@@ -0,0 +1,20 @@
export const up = (pgm) => {
pgm.sql(`
CREATE TABLE users (
id UUID PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
role_id UUID,
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
FOREIGN KEY (role_id) REFERENCES roles(id)
);
`)
}
export const down = (pgm) => {
pgm.sql(`
DROP TABLE users;
`)
}
+42
View File
@@ -0,0 +1,42 @@
{
"name": "tcg-collectors-server",
"version": "1.0.0",
"description": "A basic Express application with PostgreSQL integration.",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --config prettier.config.js --write .",
"migrate": "node-pg-migrate"
},
"type": "module",
"keywords": [
"express",
"node.js",
"postgres",
"postgresql",
"database"
],
"author": "Your Name",
"license": "MIT",
"dependencies": {
"csv-parser": "^3.0.0",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"node-pg": "^1.0.1",
"p-limit": "^7.3.0",
"pg": "^8.20.0"
},
"devDependencies": {
"eslint": "^10.3.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.5",
"jest": "^29.0.0",
"node-pg-migrate": "^8.0.4",
"nodemon": "^3.0.0",
"prettier": "^3.8.3"
}
}
+8
View File
@@ -0,0 +1,8 @@
// prettier.config.js
export default {
trailingComma: 'es5',
tabWidth: 2,
semi: false, // Crucial: Sets semicolon removal.
useTabs: true,
singleQuote: true,
}