diff --git a/Dockerfile b/Dockerfile index f20963d..006706c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,10 +56,10 @@ RUN apk add --no-cache --virtual .runtime-deps \ WORKDIR /app # Copy backend -COPY ./backend/ /app/backend/ +COPY --chown=app:app ./backend/ /app/backend/ RUN chmod +x /app/backend/cmd/start.sh -COPY ./scripts/docker-entrypoint.sh /app/scripts/docker-entrypoint.sh +COPY --chown=app:app ./scripts/docker-entrypoint.sh /app/scripts/docker-entrypoint.sh RUN chmod +x /app/scripts/docker-entrypoint.sh # Copy frontend @@ -70,8 +70,7 @@ COPY --from=builder --chown=app:app /app/node_modules ./node_modules COPY --from=builder --chown=app:app /app/package.json /app/ # Create necessary directories -RUN mkdir -p /app/backend/db /app/backend/certs && \ - chown -R app:app /app +RUN mkdir -p /app/backend/db /app/backend/certs # Cleanup RUN apk del --no-cache .runtime-deps sqlite openssl curl && \ @@ -84,6 +83,7 @@ VOLUME ["/app/backend/db"] EXPOSE 3002 ENV NODE_ENV=production \ + DB_FILE="db/production.sqlite3" \ PORT=3002 \ TUDUDI_INTERNAL_SSL_ENABLED=false \ TUDUDI_ALLOWED_ORIGINS="http://localhost:8080,http://localhost:3002,http://127.0.0.1:8080,http://127.0.0.1:3002" \ diff --git a/backend/app.js b/backend/app.js index 560ae5c..fb50946 100644 --- a/backend/app.js +++ b/backend/app.js @@ -10,7 +10,8 @@ const SequelizeStore = require('connect-session-sequelize')(session.Store); const { sequelize } = require('./models'); const { initializeTelegramPolling } = require('./services/telegramInitializer'); const taskScheduler = require('./services/taskScheduler'); -const config = require('./config/config'); +const { setConfig, getConfig } = require('./config/config'); +const config = getConfig(); const app = express(); diff --git a/backend/cmd/start.sh b/backend/cmd/start.sh index 2561906..c7b518c 100755 --- a/backend/cmd/start.sh +++ b/backend/cmd/start.sh @@ -1,9 +1,6 @@ #!/bin/sh set -eu -DB_FILE="db/production.sqlite3" -[ "$NODE_ENV" = "development" ] && DB_FILE="db/development.sqlite3" - # Check if database exists and create/authenticate if [ ! -f "$DB_FILE" ]; then echo "Creating new database..." diff --git a/backend/config/config.js b/backend/config/config.js index 8af2f48..fb3bd9e 100644 --- a/backend/config/config.js +++ b/backend/config/config.js @@ -14,9 +14,6 @@ if ( const environment = process.env.NODE_ENV; const production = process.env.NODE_ENV === 'production'; const projectRootPath = path.join(__dirname, '..'); // backend root path -const dbDir = process.env.DATABASE_URL - ? process.env.DATABASE_URL.replace('sqlite:///', '') - : path.join(projectRootPath, 'db'); const credentials = { google: { @@ -40,9 +37,9 @@ const config = { 'http://127.0.0.1:9292', ], - dbDir, - - dbFile: path.join(dbDir, `${environment}.sqlite3`), + dbFile: + process.env.DB_FILE || + path.join(projectRootPath, 'db', `${environment}.sqlite3`), disableScheduler: process.env.DISABLE_SCHEDULER === 'true', @@ -72,6 +69,16 @@ const config = { production && process.env.TUDUDI_INTERNAL_SSL_ENABLED === 'true', }; -// Configuration logging removed for cleaner test output +console.log(`Using database file '${config.dbFile}'`); -module.exports = config; +function setConfig({ dbFile } = {}) { + if (dbFile != null) { + config.dbFile = dbFile; + } +} + +function getConfig() { + return config; +} + +module.exports = { setConfig, getConfig }; diff --git a/backend/config/database.js b/backend/config/database.js index fe350f0..6575333 100644 --- a/backend/config/database.js +++ b/backend/config/database.js @@ -1,11 +1,12 @@ require('dotenv').config(); const path = require('path'); -const config = require('./config'); +const { setConfig, getConfig } = require('../config/config'); +const config = getConfig(); module.exports = { development: { dialect: 'sqlite', - storage: path.join(config.dbDir, 'development.sqlite3'), + storage: config.dbFile, logging: console.log, define: { timestamps: true, @@ -16,7 +17,7 @@ module.exports = { }, test: { dialect: 'sqlite', - storage: path.join(config.dbDir, 'test.sqlite3'), + storage: config.dbFile, logging: false, define: { timestamps: true, @@ -27,7 +28,7 @@ module.exports = { }, production: { dialect: 'sqlite', - storage: path.join(config.dbDir, 'production.sqlite3'), + storage: config.dbFile, logging: false, define: { timestamps: true, diff --git a/backend/jest.config.js b/backend/jest.config.js index 0c2fdd4..fbc6020 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -2,7 +2,6 @@ module.exports = { testEnvironment: 'node', setupFilesAfterEnv: ['/tests/helpers/setup.js'], testMatch: ['/tests/**/*.test.js', '/tests/**/*.spec.js'], - maxWorkers: 1, collectCoverageFrom: [ 'routes/**/*.js', 'models/**/*.js', diff --git a/backend/models/calendar_token.js b/backend/models/calendar_token.js index 74a88c9..e7354cd 100644 --- a/backend/models/calendar_token.js +++ b/backend/models/calendar_token.js @@ -1,5 +1,5 @@ const { DataTypes } = require('sequelize'); -const sequelize = require('../config/database'); +const { sequelize } = require('./models'); const CalendarToken = sequelize.define( 'CalendarToken', diff --git a/backend/models/index.js b/backend/models/index.js index 11d5fa4..1315f80 100644 --- a/backend/models/index.js +++ b/backend/models/index.js @@ -1,6 +1,7 @@ const { Sequelize } = require('sequelize'); const path = require('path'); -const config = require('../config/config'); +const { getConfig } = require('../config/config'); +const config = getConfig(); // Database configuration let dbConfig; diff --git a/backend/routes/auth.js b/backend/routes/auth.js index 998bdc2..1a231d6 100644 --- a/backend/routes/auth.js +++ b/backend/routes/auth.js @@ -57,6 +57,13 @@ router.post('/login', async (req, res) => { req.session.userId = user.id; + await new Promise((resolve, reject) => { + req.session.save((err) => { + if (err) reject(err); + else resolve(); + }); + }); + res.json({ user: { id: user.id, diff --git a/backend/routes/calendar.js b/backend/routes/calendar.js index 8d2f6da..f20286f 100644 --- a/backend/routes/calendar.js +++ b/backend/routes/calendar.js @@ -2,7 +2,8 @@ const express = require('express'); const router = express.Router(); const { google } = require('googleapis'); const { requireAuth } = require('../middleware/auth'); -const config = require('../config/config'); +const { setConfig, getConfig } = require('../config/config'); +const config = getConfig(); // Google Calendar configuration const SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']; diff --git a/backend/scripts/seed-dev-data.js b/backend/scripts/seed-dev-data.js index 55605b6..3f48fac 100644 --- a/backend/scripts/seed-dev-data.js +++ b/backend/scripts/seed-dev-data.js @@ -2,7 +2,8 @@ const path = require('path'); const { seedDatabase } = require('../seeders/dev-seeder'); -const config = require('../config/config'); +const { setConfig, getConfig } = require('../config/config'); +const config = getConfig(); console.log('🌱 Starting development data seeding...'); console.log(`📁 Database: ${config.dbFile}`); diff --git a/backend/services/taskScheduler.js b/backend/services/taskScheduler.js index bacbda4..10adadb 100644 --- a/backend/services/taskScheduler.js +++ b/backend/services/taskScheduler.js @@ -2,7 +2,8 @@ const cron = require('node-cron'); const { User } = require('../models'); const TaskSummaryService = require('./taskSummaryService'); const RecurringTaskService = require('./recurringTaskService'); -const config = require('../config/config'); +const { setConfig, getConfig } = require('../config/config'); +const config = getConfig(); // Create scheduler state const createSchedulerState = () => ({ diff --git a/backend/services/telegramInitializer.js b/backend/services/telegramInitializer.js index 706e4f6..1c15522 100644 --- a/backend/services/telegramInitializer.js +++ b/backend/services/telegramInitializer.js @@ -1,6 +1,7 @@ const telegramPoller = require('./telegramPoller'); const { User } = require('../models'); -const config = require('../config/config'); +const { setConfig, getConfig } = require('../config/config'); +const config = getConfig(); async function initializeTelegramPolling() { if (config.environment === 'test' || config.disableTelegram) { diff --git a/backend/tests/helpers/setup.js b/backend/tests/helpers/setup.js index b405983..f289a23 100644 --- a/backend/tests/helpers/setup.js +++ b/backend/tests/helpers/setup.js @@ -1,6 +1,9 @@ -// Set test environment before importing models -process.env.NODE_ENV = 'test'; +// This file is run once per each Jest worker, +// so changing the DB in the beginning of this file +// works. +const testId = require('crypto').randomBytes(4).toString('hex'); +process.env.DB_FILE = `/tmp/test-${testId}.sqlite3`; const { sequelize } = require('../../models'); beforeAll(async () => { diff --git a/backend/tests/integration/auth.test.js b/backend/tests/integration/auth.test.js index 709a734..43e19e0 100644 --- a/backend/tests/integration/auth.test.js +++ b/backend/tests/integration/auth.test.js @@ -1,6 +1,6 @@ const request = require('supertest'); const app = require('../../app'); -const { User } = require('../../models'); +require('../../models'); const { createTestUser } = require('../helpers/testUtils'); describe('Auth Routes', () => { diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh index 87512ca..d3db339 100644 --- a/scripts/docker-entrypoint.sh +++ b/scripts/docker-entrypoint.sh @@ -45,6 +45,7 @@ if [ "$CURRENT_UID" != "$PUID" ] || [ "$CURRENT_GID" != "$PGID" ]; then mkdir -p /app/backend/db /app/backend/certs chown -R app:$TARGET_GROUP /app/backend/db /app/backend/certs chmod 770 /app/backend/db /app/backend/certs + chmod 660 "$DB_FILE" echo "User configuration completed" else