Datepicker redesign + DB connection fixes for Prod

This commit is contained in:
AG
2025-12-18 20:49:34 +02:00
parent 3a8f132b91
commit b6cb3059af
10 changed files with 472 additions and 78 deletions

View File

@@ -0,0 +1,29 @@
const { PrismaBetterSqlite3 } = require('@prisma/adapter-better-sqlite3');
const path = require('path');
async function check() {
console.log('--- Prisma Adapter Diagnostic ---');
const factory = new PrismaBetterSqlite3({ url: 'file:./dev.db' });
console.log('Factory Properties:');
console.log(Object.keys(factory));
console.log('Factory.adapterName:', factory.adapterName);
console.log('Factory.provider:', factory.provider);
try {
const adapter = await factory.connect();
console.log('\nAdapter Properties:');
console.log(Object.keys(adapter));
console.log('Adapter name:', adapter.adapterName);
console.log('Adapter provider:', adapter.provider);
// Also check if there are hidden/prototype properties
let proto = Object.getPrototypeOf(adapter);
console.log('Adapter Prototype Properties:', Object.getOwnPropertyNames(proto));
} catch (e) {
console.error('Failed to connect:', e);
}
}
check();

45
server/check_db_perms.js Normal file
View File

@@ -0,0 +1,45 @@
const fs = require('fs');
const path = require('path');
const dbPath = path.resolve(__dirname, 'prod.db');
const dirPath = __dirname;
console.log('--- GymFlow Database Permission Check ---');
console.log(`Checking directory: ${dirPath}`);
console.log(`Checking file: ${dbPath}`);
// 1. Check Directory
try {
fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK);
console.log('✅ Directory is readable and writable.');
} catch (err) {
console.error('❌ Directory is NOT writable! SQLite needs directory write access to create temporary files.');
}
// 2. Check File
if (fs.existsSync(dbPath)) {
try {
fs.accessSync(dbPath, fs.constants.R_OK | fs.constants.W_OK);
console.log('✅ Database file is readable and writable.');
} catch (err) {
console.error('❌ Database file is NOT writable!');
}
} else {
console.log(' Database file does not exist yet.');
}
// 3. Try to write a test file in the directory
const testFile = path.join(dirPath, '.write_test');
try {
fs.writeFileSync(testFile, 'test');
fs.unlinkSync(testFile);
console.log('✅ Successfully performed a test write in the directory.');
} catch (err) {
console.error(`❌ Failed test write in directory: ${err.message}`);
}
console.log('\n--- Recommendation ---');
console.log('If any checks failed, run these commands on your NAS (in the gymflow/server folder):');
console.log('1. sudo chmod 777 .');
console.log('2. sudo chmod 666 prod.db');
console.log('\nAlternatively, ensure your Docker container is running with a user that owns these files.');

Binary file not shown.

Binary file not shown.

View File

@@ -54,10 +54,33 @@ async function resetDb() {
// 4. Create the Admin user
console.log(`Creating fresh admin user...`);
// In Prisma 7, we must use the adapter for better-sqlite3
// In Prisma 7, PrismaBetterSqlite3 is a factory.
// We use the factory to create the adapter, then we access the internal client
// to disable WAL mode for NAS/Network share compatibility (journal_mode = DELETE).
const { PrismaBetterSqlite3 } = require('@prisma/adapter-better-sqlite3');
const adapter = new PrismaBetterSqlite3({ url: dbPath });
const prisma = new PrismaClient({ adapter });
const factory = new PrismaBetterSqlite3({ url: dbPath });
const adapterWrapper = {
provider: 'sqlite',
adapterName: '@prisma/adapter-better-sqlite3',
async connect() {
const adapter = await factory.connect();
if (adapter.client) {
console.log(`Setting journal_mode = DELETE for NAS compatibility`);
adapter.client.pragma('journal_mode = DELETE');
}
return adapter;
},
async connectToShadowDb() {
const adapter = await factory.connectToShadowDb();
if (adapter.client) {
adapter.client.pragma('journal_mode = DELETE');
}
return adapter;
}
};
const prisma = new PrismaClient({ adapter: adapterWrapper });
try {
const hashedPassword = await bcrypt.hash(adminPassword, 10);

View File

@@ -35,13 +35,36 @@ console.log('Initializing Prisma Client with database:', dbPath);
let prisma: PrismaClient;
// In Prisma 7, PrismaBetterSqlite3 is a factory.
// We use a wrapper to intercept the connection and disable WAL mode
// for NAS/Network share compatibility (journal_mode = DELETE).
try {
const adapter = new PrismaBetterSqlite3({ url: dbPath });
const factory = new PrismaBetterSqlite3({ url: dbPath });
const adapterWrapper = {
provider: 'sqlite',
adapterName: '@prisma/adapter-better-sqlite3',
async connect() {
const adapter = (await factory.connect()) as any;
if (adapter.client) {
console.log('[Prisma] Setting journal_mode = DELETE for NAS compatibility');
adapter.client.pragma('journal_mode = DELETE');
}
return adapter;
},
async connectToShadowDb() {
const adapter = (await factory.connectToShadowDb()) as any;
if (adapter.client) {
adapter.client.pragma('journal_mode = DELETE');
}
return adapter;
}
};
prisma =
global.prisma ||
new PrismaClient({
adapter: adapter as any,
adapter: adapterWrapper as any,
});
} catch (e: any) {
console.error('Failed to initialize Prisma Client:', e.message);