working on healthcheck api and auth api (#2)

Reviewed-on: #2
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 #2.
This commit is contained in:
2026-05-15 22:37:27 -07:00
committed by joseph.nelson4456
parent ce914f91fd
commit 2636816241
16 changed files with 151 additions and 36 deletions
+28
View File
@@ -0,0 +1,28 @@
import express from 'express'
import path from 'path'
import cors from 'cors'
import healthCheckRoutes from './routes/healthcheck'
import authRoutes from './routes/auth'
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
app.use(cors())
// Mount Routes
app.use('/healthcheck', healthCheckRoutes)
app.use('/auth', authRoutes)
// 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}`)
})
export default app
+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,
},
}
+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;
`)
}
@@ -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;
`)
}
@@ -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;
`)
}
+75
View File
@@ -0,0 +1,75 @@
import express from 'express'
import jwt from 'jsonwebtoken'
import bcrypt from 'bcryptjs'
import { database } from '../../config'
const { Pool } = require('pg')
const router = express.Router()
// Database connection pool
const pool = new Pool(database)
// Route to handle login and issue JWT token
router.post('/login', async (req, res) => {
const { username, password } = req.body
try {
const client = await pool.connect()
const queryText = 'SELECT * FROM users WHERE username = $1'
const result = await client.query(queryText, [username])
if (!result.rows.length) {
return res.status(401).json({ message: 'Invalid credentials' })
}
const user = result.rows[0]
// Compare passwords
const passwordMatch = await bcrypt.compare(password, user.password)
if (!passwordMatch) {
return res.status(401).json({ message: 'Invalid credentials' })
}
// Issue JWT token
const token = jwt.sign(
{ id: user.id, username: user.username },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
)
res.json({ token })
} catch (error) {
console.error(error)
res.status(500).json({ message: 'Internal server error' })
}
})
// Route to refresh JWT token
router.post('/refresh-token', async (req, res) => {
const { refreshToken } = req.body
if (!refreshToken) {
return res.status(401).json({ message: 'Refresh token is required' })
}
try {
// Verify the refresh token
const decoded = jwt.verify(refreshToken, process.env.JWT_SECRET)
// Create a new access token (JWT)
const token = jwt.sign(
{ id: decoded.id, username: decoded.username },
process.env.JWT_SECRET,
{ expiresIn: '1h' }
)
res.json({ token })
} catch (error) {
console.error(error)
res.status(403).json({ message: 'Invalid refresh token' })
}
})
export default router
+7
View File
@@ -0,0 +1,7 @@
import express from 'express'
const router = express.Router()
router.get('/', (req, res) => res.json({ status: 'UP' }))
export default router
+19
View File
@@ -0,0 +1,19 @@
// src/routes/healthcheck/test.js
import request from 'supertest'
import app from '../../app'
describe('Health Check Endpoint', () => {
it('should respond with status up', async () => {
const response = await request(app).get('/healthcheck')
expect(response.status).toBe(200)
expect(response.body).toEqual({ status: 'UP' })
})
it('should return a JSON response', async () => {
const response = await request(app).get('/healthcheck')
expect(response.type).toBe('application/json')
})
})