mirror of
https://github.com/papra-hq/papra.git
synced 2025-12-21 12:09:39 -06:00
feat(script): ensure local database directory exists before running scripts (#337)
This commit is contained in:
committed by
GitHub
parent
ff830c234a
commit
1c574b8305
5
.changeset/brown-jars-walk.md
Normal file
5
.changeset/brown-jars-walk.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@papra/app-server": patch
|
||||
---
|
||||
|
||||
Ensure database directory exists when running scripts (like migrations)
|
||||
5
.changeset/old-dancers-study.md
Normal file
5
.changeset/old-dancers-study.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@papra/docs": minor
|
||||
---
|
||||
|
||||
Added troubleshooting page
|
||||
5
.changeset/wide-clubs-occur.md
Normal file
5
.changeset/wide-clubs-occur.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@papra/docs": patch
|
||||
---
|
||||
|
||||
Added `docker compose up` command in dc generator
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Troubleshooting
|
||||
description: Troubleshooting guide for Papra
|
||||
slug: resources/troubleshooting
|
||||
---
|
||||
|
||||
You can find here some common issues and how to fix them. If you encounter an issue that is not listed here, please [open an issue](https://github.com/papra-hq/papra/issues/new/choose) or [join our Discord](https://papra.app/discord).
|
||||
|
||||
## Failed to ensure that the database directory exists
|
||||
|
||||
Upon starting the server or a script, you may encounter this error
|
||||
|
||||
```
|
||||
Failed to ensure that the database directory exists, error while creating the directory
|
||||
Error: EACCES: permission denied, mkdir './app-data/db'
|
||||
|
||||
```
|
||||
|
||||
Before accessing the DB sqlite file, the server will try to ensure that the database directory exists, and if it doesn't, it try will create it. But in case of insufficient permissions, it will fail.
|
||||
|
||||
To fix this, you can either:
|
||||
|
||||
- Create the directory manually `mkdir -p <your-app-data-dir>/db`
|
||||
- Ensure that the directory is owned by the user running the container
|
||||
- Run the server as root (not recommended)
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,10 @@ export const sidebar: StarlightUserConfig['sidebar'] = [
|
||||
{
|
||||
label: 'Resources',
|
||||
items: [
|
||||
{
|
||||
label: 'Troubleshooting',
|
||||
slug: 'resources/troubleshooting',
|
||||
},
|
||||
{
|
||||
label: 'CLI Documentation',
|
||||
slug: 'resources/cli',
|
||||
|
||||
@@ -24,6 +24,7 @@ services:
|
||||
`.trim();
|
||||
|
||||
const dcHtml = await codeToHtml(defaultDockerCompose, { theme: 'vitesse-black', lang: 'yaml' });
|
||||
const defaultCommand = `mkdir -p ./app-data/{db,documents} && docker compose up -d`;
|
||||
---
|
||||
|
||||
|
||||
@@ -145,9 +146,12 @@ const dcHtml = await codeToHtml(defaultDockerCompose, { theme: 'vitesse-black',
|
||||
|
||||
<div id="docker-compose-output" class="mt-12" set:html={dcHtml} />
|
||||
|
||||
<pre id="command-output" class="bg-card p-4 rounded-md text-muted-foreground text-sm font-mono overflow-x-auto">{defaultCommand}</pre>
|
||||
|
||||
<div class="flex items-center gap-2 mt-4">
|
||||
<button class="btn bg-muted mt-0" id="download-button">Download docker-compose.yml</button>
|
||||
<button class="btn bg-muted mt-0" id="copy-button">Copy to clipboard</button>
|
||||
<button class="btn bg-muted mt-0" id="copy-button">Copy docker compose to clipboard</button>
|
||||
<button class="btn bg-muted mt-0" id="copy-command-button">Copy command</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -178,6 +182,8 @@ const owlrelayWebhookUrlInput = document.getElementById('intake-email-owlrelay-w
|
||||
const cfEmailDomainInput = document.getElementById('intake-email-cf-email-domain') as HTMLInputElement;
|
||||
const webhookSecretInput = document.getElementById('intake-email-webhook-secret') as HTMLInputElement;
|
||||
const refreshWebhookSecretButton = document.getElementById('refresh-webhook-secret');
|
||||
const commandOutput = document.getElementById('command-output');
|
||||
const copyCommandButton = document.getElementById('copy-command-button');
|
||||
|
||||
// Track whether the app base URL has been customized by the user
|
||||
let isAppBaseUrlCustomized = false;
|
||||
@@ -321,14 +327,31 @@ function getDockerComposeYml() {
|
||||
return stringify(dc);
|
||||
}
|
||||
|
||||
function getStartCommand() {
|
||||
const volumePath = volumePathInput.value;
|
||||
const volumePathNormalized = volumePath.replace(/\/$/, '');
|
||||
const volumeWithSubdirs = `${volumePathNormalized}/{db,documents}`;
|
||||
|
||||
const mkdirCommand = `mkdir -p ${volumeWithSubdirs}`;
|
||||
|
||||
const dockerCommand = 'docker compose up -d';
|
||||
|
||||
return `${mkdirCommand} && ${dockerCommand}`;
|
||||
}
|
||||
|
||||
async function updateDockerCompose() {
|
||||
const dockerCompose = getDockerComposeYml();
|
||||
const command = getStartCommand();
|
||||
|
||||
const html = await codeToHtml(dockerCompose, { theme: 'vitesse-black', lang: 'yaml' });
|
||||
|
||||
if (dockerComposeOutput) {
|
||||
dockerComposeOutput.innerHTML = html;
|
||||
}
|
||||
|
||||
if (commandOutput) {
|
||||
commandOutput.textContent = command;
|
||||
}
|
||||
}
|
||||
|
||||
function handleCopy() {
|
||||
@@ -420,6 +443,22 @@ function handleRefreshWebhookSecret() {
|
||||
updateDockerCompose();
|
||||
}
|
||||
|
||||
function handleCopyCommand() {
|
||||
const command = getStartCommand();
|
||||
|
||||
copyToClipboard(command);
|
||||
|
||||
if (copyCommandButton) {
|
||||
copyCommandButton.textContent = 'Copied!';
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
if (copyCommandButton) {
|
||||
copyCommandButton.textContent = 'Copy command';
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// Add event listeners
|
||||
portInput.addEventListener('input', handlePortChange);
|
||||
sourceSelect.addEventListener('change', updateDockerCompose);
|
||||
@@ -440,6 +479,7 @@ owlrelayWebhookUrlInput.addEventListener('input', handleWebhookUrlChange);
|
||||
cfEmailDomainInput.addEventListener('input', updateDockerCompose);
|
||||
webhookSecretInput.addEventListener('input', updateDockerCompose);
|
||||
refreshWebhookSecretButton?.addEventListener('click', handleRefreshWebhookSecret);
|
||||
copyCommandButton?.addEventListener('click', handleCopyCommand);
|
||||
|
||||
authSecretInput.value = getRandomString();
|
||||
|
||||
|
||||
@@ -31,6 +31,6 @@ export async function ensureLocalDatabaseDirectoryExists({ config }: { config: C
|
||||
logger.info({ dbUrl: url, dbDir, dbPath }, 'Database directory missing, created it');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error({ error, dbDir, dbPath }, 'Failed to ensure that the database directory exists, error while creating the directory');
|
||||
logger.error({ error, dbDir, dbPath }, 'Failed to ensure that the database directory exists, error while creating the directory. Please see https://docs.papra.app/resources/troubleshooting/#failed-to-ensure-that-the-database-directory-exists for more information.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { Config } from '../../modules/config/config.types';
|
||||
import type { Logger } from '../../modules/shared/logger/logger';
|
||||
import process from 'node:process';
|
||||
import { setupDatabase } from '../../modules/app/database/database';
|
||||
import { ensureLocalDatabaseDirectoryExists } from '../../modules/app/database/database.services';
|
||||
import { parseConfig } from '../../modules/config/config';
|
||||
import { createLogger, wrapWithLoggerContext } from '../../modules/shared/logger/logger';
|
||||
|
||||
@@ -23,6 +24,7 @@ async function runScript(
|
||||
const logger = createLogger({ namespace: 'scripts' });
|
||||
|
||||
const { config } = await parseConfig({ env: process.env });
|
||||
await ensureLocalDatabaseDirectoryExists({ config });
|
||||
const { db, client } = setupDatabase({ ...config.database });
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user