Compare commits
2 Commits
f5c37615ab
...
bed53dbbd3
| Author | SHA1 | Date | |
|---|---|---|---|
| bed53dbbd3 | |||
| 27802f4bf3 |
5
backend/.gitignore
vendored
Normal file
5
backend/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
# Keep environment variables out of version control
|
||||
.env
|
||||
|
||||
/src/generated/prisma
|
||||
21
backend/eslint.config.js
Normal file
21
backend/eslint.config.js
Normal file
@ -0,0 +1,21 @@
|
||||
const globals = require('globals');
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
files: ['**/*.js'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'commonjs',
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
||||
'no-console': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
ignores: ['node_modules/**', 'dist/**'],
|
||||
},
|
||||
];
|
||||
3116
backend/package-lock.json
generated
Normal file
3116
backend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
backend/package.json
Normal file
29
backend/package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"version": "1.0.0",
|
||||
"description": "Book Reading Tracker - Backend API",
|
||||
"main": "src/server.js",
|
||||
"scripts": {
|
||||
"dev": "nodemon src/server.js",
|
||||
"start": "node src/server.js",
|
||||
"lint": "eslint .",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@prisma/client": "^7.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^17.2.3",
|
||||
"express": "^5.2.1",
|
||||
"express-validator": "^7.3.1",
|
||||
"helmet": "^8.1.0",
|
||||
"prisma": "^7.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^9.39.1",
|
||||
"globals": "^16.5.0",
|
||||
"nodemon": "^3.1.11"
|
||||
}
|
||||
}
|
||||
14
backend/prisma.config.ts
Normal file
14
backend/prisma.config.ts
Normal file
@ -0,0 +1,14 @@
|
||||
// This file was generated by Prisma and assumes you have installed the following:
|
||||
// npm install --save-dev prisma dotenv
|
||||
import "dotenv/config";
|
||||
import { defineConfig, env } from "prisma/config";
|
||||
|
||||
export default defineConfig({
|
||||
schema: "prisma/schema.prisma",
|
||||
migrations: {
|
||||
path: "prisma/migrations",
|
||||
},
|
||||
datasource: {
|
||||
url: env("DATABASE_URL"),
|
||||
},
|
||||
});
|
||||
43
backend/prisma/schema.prisma
Normal file
43
backend/prisma/schema.prisma
Normal file
@ -0,0 +1,43 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
model Book {
|
||||
id Int @id @default(autoincrement())
|
||||
title String @db.VarChar(500)
|
||||
author String? @db.VarChar(500)
|
||||
totalPages Int
|
||||
coverUrl String? @db.VarChar(1000)
|
||||
deadlineDate DateTime @db.Date
|
||||
isPrimary Boolean @default(false)
|
||||
status String @default("reading") @db.VarChar(50)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
readingLogs ReadingLog[]
|
||||
|
||||
@@index([deadlineDate])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model ReadingLog {
|
||||
id Int @id @default(autoincrement())
|
||||
bookId Int
|
||||
logDate DateTime @db.Date
|
||||
currentPage Int
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
book Book @relation(fields: [bookId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([bookId, logDate])
|
||||
@@index([bookId])
|
||||
@@index([logDate])
|
||||
}
|
||||
51
backend/src/server.js
Normal file
51
backend/src/server.js
Normal file
@ -0,0 +1,51 @@
|
||||
require('dotenv').config();
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const helmet = require('helmet');
|
||||
|
||||
const app = express();
|
||||
|
||||
// Middleware
|
||||
app.use(helmet());
|
||||
app.use(
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
|
||||
credentials: true,
|
||||
})
|
||||
);
|
||||
app.use(express.json());
|
||||
|
||||
// Health check endpoint
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'ok',
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
});
|
||||
|
||||
// Error handling middleware
|
||||
app.use((err, req, res, _next) => {
|
||||
console.error('Error:', err);
|
||||
|
||||
// Validation errors (from express-validator)
|
||||
if (err.errors && Array.isArray(err.errors)) {
|
||||
return res.status(400).json({
|
||||
error: 'Validation failed',
|
||||
details: err.errors,
|
||||
});
|
||||
}
|
||||
|
||||
// Default error response
|
||||
res.status(err.statusCode || 500).json({
|
||||
error: err.message || 'Internal server error',
|
||||
});
|
||||
});
|
||||
|
||||
// Start server
|
||||
const PORT = process.env.API_PORT || 3000;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on http://localhost:${PORT}`);
|
||||
console.log(`Health check: http://localhost:${PORT}/api/health`);
|
||||
});
|
||||
|
||||
module.exports = app;
|
||||
Loading…
x
Reference in New Issue
Block a user