Fix SQLite init: lazy loading, writability check, and host permissions
All checks were successful
Deploy Website / build-and-deploy (push) Successful in 30s

DB initialization was eager at module import time, crashing the entire
analytics route when /server_storage wasn't writable. Now deferred to
first logVisit() call with graceful fallback. Also fix deploy workflow
to chown via a bind-mounted container so permissions apply on the host.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shivam Patel
2026-02-09 00:17:44 -05:00
parent 4a01928fe7
commit 9cf5f9620c
2 changed files with 45 additions and 25 deletions

View File

@@ -24,14 +24,10 @@ jobs:
- name: Prepare Host Storage - name: Prepare Host Storage
run: | run: |
# 1. Create the host folder if it doesn't exist # The bind mount creates /server_storage on the host if missing.
sudo mkdir -p /server_storage # Run a throwaway container to fix ownership so UID 1001 (nextjs) can write.
docker run --rm -v /server_storage:/data alpine sh -c \
# 2. Fix permissions for the 'nextjs' user (UID 1001) "chown -R 1001:1001 /data && chmod -R 755 /data"
# Since your Dockerfile runs as user 1001, it cannot write to
# a root-owned folder without this chown command.
sudo chown -R 1001:1001 /server_storage
sudo chmod -R 755 /server_storage
- name: Run New Container - name: Run New Container
run: | run: |

View File

@@ -1,28 +1,52 @@
import Database from 'better-sqlite3'; import Database from 'better-sqlite3';
import type BetterSqlite3 from 'better-sqlite3';
import path from 'path'; import path from 'path';
import fs from 'fs'; import fs from 'fs';
const SERVER_STORAGE = '/server_storage'; let db: BetterSqlite3.Database | null = null;
const dbPath = fs.existsSync(SERVER_STORAGE) let insertStmt: BetterSqlite3.Statement | null = null;
? path.join(SERVER_STORAGE, 'visitors.db')
: path.join(process.cwd(), 'visitors.db');
const db = new Database(dbPath); function getDb() {
db.pragma('journal_mode = WAL'); if (db) return db;
db.exec(` try {
CREATE TABLE IF NOT EXISTS visits ( const SERVER_STORAGE = '/server_storage';
id INTEGER PRIMARY KEY AUTOINCREMENT, let dbDir: string;
ip_address TEXT NOT NULL, try {
path TEXT NOT NULL, fs.accessSync(SERVER_STORAGE, fs.constants.W_OK);
visited_at TEXT NOT NULL DEFAULT (datetime('now')) dbDir = SERVER_STORAGE;
); } catch {
`); dbDir = process.cwd();
}
const insertStmt = db.prepare( const dbPath = path.join(dbDir, 'visitors.db');
'INSERT INTO visits (ip_address, path) VALUES (?, ?)' db = new Database(dbPath);
); db.pragma('journal_mode = WAL');
db.exec(`
CREATE TABLE IF NOT EXISTS visits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ip_address TEXT NOT NULL,
path TEXT NOT NULL,
visited_at TEXT NOT NULL DEFAULT (datetime('now'))
);
`);
insertStmt = db.prepare(
'INSERT INTO visits (ip_address, path) VALUES (?, ?)'
);
return db;
} catch (e) {
console.error('Failed to initialize SQLite database:', e);
db = null;
insertStmt = null;
return null;
}
}
export function logVisit(ip: string, visitPath: string) { export function logVisit(ip: string, visitPath: string) {
const database = getDb();
if (!database || !insertStmt) return;
insertStmt.run(ip, visitPath); insertStmt.run(ip, visitPath);
} }