Skip to content

feat: add e2e tests to backup/restore databases.#292

Open
KillianLarcher wants to merge 22 commits into
mainfrom
feat/database-e2e
Open

feat: add e2e tests to backup/restore databases.#292
KillianLarcher wants to merge 22 commits into
mainfrom
feat/database-e2e

Conversation

@KillianLarcher
Copy link
Copy Markdown
Collaborator

@KillianLarcher KillianLarcher commented May 20, 2026

Summary by CodeRabbit

  • Tests

    • Enhanced end-to-end testing infrastructure with automated backup and restore workflows across multiple database engines (PostgreSQL, MySQL, MariaDB, MongoDB).
    • Added new testing utilities for validating backup and restoration operations through the dashboard.
  • Chores

    • Updated environment and Docker configurations for E2E testing.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR establishes end-to-end testing infrastructure for validating backup and restore functionality across multiple database engines and versions. It introduces Docker Compose services for PostgreSQL, MySQL, MariaDB, MongoDB, Redis, Valkey, MSSQL, and SQLite, an E2E environment configuration file with test-specific settings for authentication and notifications, Playwright helpers to automate backup/restore workflows in the dashboard UI, and a make target that orchestrates the multi-database stack with Playwright tests.

Changes

E2E Multi-Database Testing Infrastructure

Layer / File(s) Summary
Multi-Database Service Infrastructure
.env.e2e, docker-compose.database.yml, docker-compose.e2e.yml
E2E environment configuration defines runtime, logging, database, SMTP, OIDC/OAuth, notifications (SMTP, Slack, Discord, Telegram, Gotify, NTFY, webhook), and storage backends (S3, R2, Google Drive). docker-compose.database.yml defines YAML anchor templates for PostgreSQL 12–18, MySQL 8.0/8.4, MariaDB 10.11–11.4, MongoDB 6.0–8.0 (auth and no-auth), Redis 7/8, Valkey 7/8, MSSQL 2019/2022, and SQLite 3.45/3.46, with per-version service instances, exposed ports, and persistent volumes. E2E compose adjusts PostgreSQL volume mount path.
E2E Test Automation & Orchestration
Makefile, e2e/helpers/backup.ts, .gitignore, src/lib/logger.ts
New e2e-backup make target orchestrates database and E2E Docker stacks, runs Playwright tests in UI mode with graceful failure teardown. e2e/helpers/backup.ts exports backupDatabases list and utilities to create projects, open database cards, trigger backups, await success, initiate restores, and verify restoration completion. Logger refactored to read NODE_ENV and LOG_LEVEL directly from process.env instead of custom env module. .worktrees added to .gitignore.

Sequence Diagram(s)

sequenceDiagram
    participant Orchestrator as e2e-backup<br/>make target
    participant DockerStacks as Docker<br/>Stacks
    participant Playwright as Playwright<br/>Test
    participant Dashboard as Dashboard UI
    participant Database as Database<br/>Service
    
    Orchestrator->>DockerStacks: compose up (e2e + database)
    Orchestrator->>Playwright: execute tests in --ui mode
    Playwright->>Dashboard: createProjectWithAllDatabases
    Dashboard->>Database: provision databases
    Playwright->>Dashboard: openProjectDatabase(dbms)
    Playwright->>Dashboard: createBackup()
    Dashboard->>Database: trigger backup
    Database-->>Dashboard: backup complete
    Playwright->>Dashboard: waitForBackupSuccess()
    Playwright->>Dashboard: createRestoreFromBackup()
    Dashboard->>Database: restore from backup
    Database-->>Dashboard: restore complete
    Playwright->>Dashboard: waitForRestoreSuccess()
    Playwright-->>Orchestrator: test results
    Orchestrator->>DockerStacks: compose down
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • Portabase/portabase#288: Modifies src/lib/logger.ts to compute isProd/defaultLevel/level from process.env instead of importing env, overlapping with the logger refactoring in this PR.
  • Portabase/portabase#236: Updates src/lib/logger.ts pino logger configuration based on process.env derivation of environment mode and log level.
  • Portabase/portabase#285: Related logger configuration changes that modify LOG_LEVEL/NODE_ENV sourcing logic in src/lib/logger.ts.

Poem

🐰 A warren of databases now dances in Docker, / PostgreSQL hops with MySQL, MariaDB talks and talks, / MongoDB springs forth with Redis valiant, / While Playwright scribes the backup ballet—restore and rehearse—all in one unified test garden! 🌱✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add e2e tests to backup/restore databases' accurately reflects the main changes: new e2e test infrastructure and helpers specifically for backup/restore database functionality.
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/database-e2e

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

e2e/helpers/backup.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///.eslintrc.json?mtime=1779306805948" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoadSync (node:internal/modules/esm/load:164:3)
at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:776:12)
at #loadSync (node:internal/modules/esm/loader:796:49)
at ModuleLoader.load (node:internal/modules/esm/loader:762:26)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:504:31)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:555:36)
at afterResolve (node:internal/modules/esm/loader:603:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:609:12)
at node:internal/modules/esm/loader:628:32

src/lib/logger.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError [ERR_IMPORT_ATTRIBUTE_MISSING]: Module "file:///.eslintrc.json?mtime=1779306805948" needs an import attribute of "type: json"
at validateAttributes (node:internal/modules/esm/assert:88:15)
at defaultLoadSync (node:internal/modules/esm/load:164:3)
at #loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:776:12)
at #loadSync (node:internal/modules/esm/loader:796:49)
at ModuleLoader.load (node:internal/modules/esm/loader:762:26)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:504:31)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:555:36)
at afterResolve (node:internal/modules/esm/loader:603:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:609:12)
at node:internal/modules/esm/loader:628:32


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Line 60: Update the Docker Compose startup command used in the Makefile target
that runs "docker compose -f docker-compose.database.yml up -d" to include the
"--wait" flag so the command blocks until services' healthchecks pass; locate
the Makefile target invoking docker compose with "-f docker-compose.database.yml
up -d" and change it to use "docker compose -f docker-compose.database.yml up
--wait -d" (or equivalent ordering) so subsequent Playwright tests run only
after the database services are healthy.
- Line 61: The e2e-backup Make target currently runs Playwright with the
interactive --ui flag; remove --ui and run Playwright non-interactively instead
by invoking pnpm playwright test with CI=true and the appropriate project flag
(for example CI=true pnpm playwright test --project=chromium) while keeping the
existing error/cleanup chaining (the docker compose down --volumes && exit 1
sequence) intact; update the command in the e2e-backup target to use this
non-interactive invocation and ensure no other interactive flags remain.

In `@src/lib/logger.ts`:
- Line 5: The logger currently reads process.env.LOG_LEVEL and casts it to
pino.Level via the const level = (process.env.LOG_LEVEL ?? defaultLevel) as
pino.Level; which bypasses validation and can crash startup; replace this by
importing the validated env object from "`@/env.mjs`" and use env.LOG_LEVEL
(falling back to defaultLevel if needed) when setting level, or alternatively
expand the env schema in env.mjs to include all pino levels and then use
env.LOG_LEVEL; update the code that defines level and any references to ensure
they use the validated value (identify the const level, defaultLevel, and any
exports from src/lib/logger.ts to modify).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 53a9047e-25fa-4c97-bcfc-5cd717a75861

📥 Commits

Reviewing files that changed from the base of the PR and between 3325404 and dd47964.

📒 Files selected for processing (8)
  • .env.e2e
  • .gitignore
  • Makefile
  • docker-compose.database.yml
  • docker-compose.e2e.yml
  • e2e/helpers/agent-cli.ts
  • e2e/helpers/backup.ts
  • src/lib/logger.ts
💤 Files with no reviewable changes (1)
  • e2e/helpers/agent-cli.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-and-test
🧰 Additional context used
🪛 checkmake (0.3.2)
Makefile

[warning] 57-57: Target body for "e2e-backup" exceeds allowed length of 5 lines (7).

(maxbodylength)

🪛 Checkov (3.2.529)
docker-compose.database.yml

[low] 54-55: Base64 High Entropy String

(CKV_SECRET_6)

🪛 dotenv-linter (4.0.0)
.env.e2e

[warning] 14-14: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 16-16: [UnorderedKey] The PROJECT_SECRET key should go before the PROJECT_URL key

(UnorderedKey)


[warning] 22-22: [UnorderedKey] The SMTP_PASSWORD key should go before the SMTP_PORT key

(UnorderedKey)


[warning] 23-23: [UnorderedKey] The SMTP_FROM key should go before the SMTP_HOST key

(UnorderedKey)


[warning] 30-30: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 31-31: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 32-32: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 32-32: [UnorderedKey] The AUTH_OIDC_DESC key should go before the AUTH_OIDC_ID key

(UnorderedKey)


[warning] 33-33: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 33-33: [UnorderedKey] The AUTH_OIDC_ICON key should go before the AUTH_OIDC_ID key

(UnorderedKey)


[warning] 34-34: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 34-34: [UnorderedKey] The AUTH_OIDC_CLIENT key should go before the AUTH_OIDC_DESC key

(UnorderedKey)


[warning] 35-35: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 35-35: [UnorderedKey] The AUTH_OIDC_SECRET key should go before the AUTH_OIDC_TITLE key

(UnorderedKey)


[warning] 36-36: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 36-36: [UnorderedKey] The AUTH_OIDC_ISSUER_URL key should go before the AUTH_OIDC_SECRET key

(UnorderedKey)


[warning] 37-37: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 37-37: [UnorderedKey] The AUTH_OIDC_HOST key should go before the AUTH_OIDC_ICON key

(UnorderedKey)


[warning] 38-38: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 38-38: [UnorderedKey] The AUTH_OIDC_SCOPES key should go before the AUTH_OIDC_SECRET key

(UnorderedKey)


[warning] 39-39: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 39-39: [UnorderedKey] The AUTH_OIDC_DISCOVERY_ENDPOINT key should go before the AUTH_OIDC_HOST key

(UnorderedKey)


[warning] 40-40: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 40-40: [UnorderedKey] The AUTH_OIDC_JWKS_ENDPOINT key should go before the AUTH_OIDC_SCOPES key

(UnorderedKey)


[warning] 41-41: [UnorderedKey] The AUTH_OIDC_PKCE key should go before the AUTH_OIDC_SCOPES key

(UnorderedKey)


[warning] 42-42: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 42-42: [UnorderedKey] The ALLOWED_GROUP key should go before the AUTH_OIDC_CLIENT key

(UnorderedKey)


[warning] 43-43: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 43-43: [UnorderedKey] The AUTH_OIDC_ROLE_MAP key should go before the AUTH_OIDC_SCOPES key

(UnorderedKey)


[warning] 47-47: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 48-48: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 49-49: [UnorderedKey] The AUTH_OIDC_KEYCLOAK_DESC key should go before the AUTH_OIDC_KEYCLOAK_ID key

(UnorderedKey)


[warning] 50-50: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 50-50: [UnorderedKey] The AUTH_OIDC_KEYCLOAK_CLIENT key should go before the AUTH_OIDC_KEYCLOAK_DESC key

(UnorderedKey)


[warning] 51-51: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 51-51: [UnorderedKey] The AUTH_OIDC_KEYCLOAK_SECRET key should go before the AUTH_OIDC_KEYCLOAK_TITLE key

(UnorderedKey)


[warning] 52-52: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 52-52: [UnorderedKey] The AUTH_OIDC_KEYCLOAK_ISSUER_URL key should go before the AUTH_OIDC_KEYCLOAK_SECRET key

(UnorderedKey)


[warning] 53-53: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 53-53: [UnorderedKey] The AUTH_OIDC_KEYCLOAK_HOST key should go before the AUTH_OIDC_KEYCLOAK_ID key

(UnorderedKey)


[warning] 54-54: [UnorderedKey] The AUTH_OIDC_KEYCLOAK_SCOPES key should go before the AUTH_OIDC_KEYCLOAK_SECRET key

(UnorderedKey)


[warning] 55-55: [UnorderedKey] The AUTH_OIDC_KEYCLOAK_PKCE key should go before the AUTH_OIDC_KEYCLOAK_SCOPES key

(UnorderedKey)


[warning] 57-57: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 58-58: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 59-59: [UnorderedKey] The AUTH_OIDC_AUTHENTIK_DESC key should go before the AUTH_OIDC_AUTHENTIK_ID key

(UnorderedKey)


[warning] 60-60: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 60-60: [UnorderedKey] The AUTH_OIDC_AUTHENTIK_CLIENT key should go before the AUTH_OIDC_AUTHENTIK_DESC key

(UnorderedKey)


[warning] 61-61: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 61-61: [UnorderedKey] The AUTH_OIDC_AUTHENTIK_SECRET key should go before the AUTH_OIDC_AUTHENTIK_TITLE key

(UnorderedKey)


[warning] 62-62: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 62-62: [UnorderedKey] The AUTH_OIDC_AUTHENTIK_ISSUER_URL key should go before the AUTH_OIDC_AUTHENTIK_SECRET key

(UnorderedKey)


[warning] 63-63: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 63-63: [UnorderedKey] The AUTH_OIDC_AUTHENTIK_HOST key should go before the AUTH_OIDC_AUTHENTIK_ID key

(UnorderedKey)


[warning] 64-64: [UnorderedKey] The AUTH_OIDC_AUTHENTIK_SCOPES key should go before the AUTH_OIDC_AUTHENTIK_SECRET key

(UnorderedKey)


[warning] 65-65: [UnorderedKey] The AUTH_OIDC_AUTHENTIK_PKCE key should go before the AUTH_OIDC_AUTHENTIK_SCOPES key

(UnorderedKey)


[warning] 67-67: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 69-69: [UnorderedKey] The AUTH_OIDC_POCKET_DESC key should go before the AUTH_OIDC_POCKET_ID key

(UnorderedKey)


[warning] 70-70: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 70-70: [UnorderedKey] The AUTH_OIDC_POCKET_CLIENT key should go before the AUTH_OIDC_POCKET_DESC key

(UnorderedKey)


[warning] 71-71: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 71-71: [UnorderedKey] The AUTH_OIDC_POCKET_SECRET key should go before the AUTH_OIDC_POCKET_TITLE key

(UnorderedKey)


[warning] 72-72: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 72-72: [UnorderedKey] The AUTH_OIDC_POCKET_ISSUER_URL key should go before the AUTH_OIDC_POCKET_SECRET key

(UnorderedKey)


[warning] 73-73: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 73-73: [UnorderedKey] The AUTH_OIDC_POCKET_HOST key should go before the AUTH_OIDC_POCKET_ID key

(UnorderedKey)


[warning] 74-74: [UnorderedKey] The AUTH_OIDC_POCKET_SCOPES key should go before the AUTH_OIDC_POCKET_SECRET key

(UnorderedKey)


[warning] 75-75: [UnorderedKey] The AUTH_OIDC_POCKET_PKCE key should go before the AUTH_OIDC_POCKET_SCOPES key

(UnorderedKey)


[warning] 80-80: [ExtraBlankLine] Extra blank line detected

(ExtraBlankLine)


[warning] 82-82: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 83-83: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 84-84: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 84-84: [UnorderedKey] The AUTH_SOCIAL_DESC key should go before the AUTH_SOCIAL_ID key

(UnorderedKey)


[warning] 85-85: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 85-85: [UnorderedKey] The AUTH_SOCIAL_ICON key should go before the AUTH_SOCIAL_ID key

(UnorderedKey)


[warning] 86-86: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 86-86: [UnorderedKey] The AUTH_SOCIAL_CLIENT key should go before the AUTH_SOCIAL_DESC key

(UnorderedKey)


[warning] 87-87: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 87-87: [UnorderedKey] The AUTH_SOCIAL_SECRET key should go before the AUTH_SOCIAL_TITLE key

(UnorderedKey)


[warning] 88-88: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 88-88: [UnorderedKey] The AUTH_SOCIAL_APPLE_APP_BUNDLE_IDENTIFIER key should go before the AUTH_SOCIAL_CLIENT key

(UnorderedKey)


[warning] 93-93: [UnorderedKey] The AUTH_EMAIL_PASSWORD_ENABLED key should go before the AUTH_SYNC_OIDC_ROLES_ON_LOGIN key

(UnorderedKey)


[warning] 94-94: [UnorderedKey] The AUTH_SIGNUP_ENABLED key should go before the AUTH_SYNC_OIDC_ROLES_ON_LOGIN key

(UnorderedKey)


[warning] 95-95: [UnorderedKey] The AUTH_PASSKEY_ENABLED key should go before the AUTH_SIGNUP_ENABLED key

(UnorderedKey)


[warning] 102-102: [ExtraBlankLine] Extra blank line detected

(ExtraBlankLine)


[warning] 103-103: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 104-104: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 105-105: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 106-106: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 106-106: [UnorderedKey] The E2E_NOTIFICATION_SMTP_PASSWORD key should go before the E2E_NOTIFICATION_SMTP_PORT key

(UnorderedKey)


[warning] 107-107: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 107-107: [UnorderedKey] The E2E_NOTIFICATION_SMTP_FROM key should go before the E2E_NOTIFICATION_SMTP_HOST key

(UnorderedKey)


[warning] 108-108: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 108-108: [UnorderedKey] The E2E_NOTIFICATION_SMTP_TO key should go before the E2E_NOTIFICATION_SMTP_USER key

(UnorderedKey)


[warning] 110-110: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 112-112: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 114-114: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 115-115: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 116-116: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 118-118: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 119-119: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 119-119: [UnorderedKey] The E2E_NOTIFICATION_GOTIFY_APP_TOKEN key should go before the E2E_NOTIFICATION_GOTIFY_SERVER_URL key

(UnorderedKey)


[warning] 121-121: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 122-122: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 122-122: [UnorderedKey] The E2E_NOTIFICATION_NTFY_SERVER_URL key should go before the E2E_NOTIFICATION_NTFY_TOPIC key

(UnorderedKey)


[warning] 123-123: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 123-123: [UnorderedKey] The E2E_NOTIFICATION_NTFY_TOKEN key should go before the E2E_NOTIFICATION_NTFY_TOPIC key

(UnorderedKey)


[warning] 124-124: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 125-125: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 125-125: [UnorderedKey] The E2E_NOTIFICATION_NTFY_PASSWORD key should go before the E2E_NOTIFICATION_NTFY_SERVER_URL key

(UnorderedKey)


[warning] 127-127: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 128-128: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 128-128: [UnorderedKey] The E2E_NOTIFICATION_WEBHOOK_SECRET_HEADER key should go before the E2E_NOTIFICATION_WEBHOOK_URL key

(UnorderedKey)


[warning] 129-129: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 129-129: [UnorderedKey] The E2E_NOTIFICATION_WEBHOOK_SECRET key should go before the E2E_NOTIFICATION_WEBHOOK_SECRET_HEADER key

(UnorderedKey)


[warning] 131-131: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 132-132: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 133-133: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 133-133: [UnorderedKey] The E2E_STORAGE_AWS_S3_ACCESS_KEY key should go before the E2E_STORAGE_AWS_S3_ENDPOINT_URL key

(UnorderedKey)


[warning] 134-134: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 135-135: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 135-135: [UnorderedKey] The E2E_STORAGE_AWS_S3_BUCKET_NAME key should go before the E2E_STORAGE_AWS_S3_ENDPOINT_URL key

(UnorderedKey)


[warning] 136-136: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 136-136: [UnorderedKey] The E2E_STORAGE_AWS_S3_PORT key should go before the E2E_STORAGE_AWS_S3_REGION key

(UnorderedKey)


[warning] 138-138: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 139-139: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 140-140: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 140-140: [UnorderedKey] The E2E_STORAGE_R2_ACCESS_KEY key should go before the E2E_STORAGE_R2_ENDPOINT_URL key

(UnorderedKey)


[warning] 141-141: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 142-142: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 142-142: [UnorderedKey] The E2E_STORAGE_R2_BUCKET_NAME key should go before the E2E_STORAGE_R2_ENDPOINT_URL key

(UnorderedKey)


[warning] 143-143: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 143-143: [UnorderedKey] The E2E_STORAGE_R2_PORT key should go before the E2E_STORAGE_R2_REGION key

(UnorderedKey)


[warning] 145-145: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 146-146: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)


[warning] 147-147: [EndingBlankLine] No blank line at the end of the file

(EndingBlankLine)


[warning] 147-147: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🔇 Additional comments (1)
docker-compose.e2e.yml (1)

24-24: ⚡ Quick win

The current mount path is correct for PostgreSQL 18—no change needed.

The project uses postgres:18-alpine, and for PostgreSQL 18+, the official Docker image recommends mounting at /var/lib/postgresql, not /var/lib/postgresql/data. This change was introduced in PostgreSQL 18 to facilitate easier major version upgrades using pg_upgrade --link. The current configuration is correct.

			> Likely an incorrect or invalid review comment.

Comment thread Makefile
e2e-backup:
@echo "Starting backup E2E testing..."
@docker compose -f docker-compose.e2e.yml up -d
@docker compose -f docker-compose.database.yml up -d
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does docker compose up --wait block until healthchecks pass for services that define healthcheck?

💡 Result:

Yes—docker compose up --wait blocks until the project’s services are “running|healthy”, and it will use each service’s healthcheck to determine when that service is healthy (if a service has a healthcheck configured). This means services that define healthcheck can delay the command until their health status becomes healthy (subject to the global --wait-timeout). [1][2][3] Notes/nuances: 1) It waits “for services to be running|healthy” (implies detached mode) rather than only “running”. [1][2] 2) For dependencies, Compose’s documented startup-order mechanism is separate (depends_on: condition: service_healthy). But --wait is broader: it can wait for all services to become healthy, not just dependencies. [4][3] 3) If a service never becomes healthy (or becomes unhealthy), --wait will stop waiting and exit non-zero; healthcheck state is what drives that behavior. [5][2] Practical answer to your question: if your compose file includes a healthcheck for a service, and you run docker compose up --wait, that service’s healthcheck must pass for the command to return successfully (within --wait-timeout). [1][2][5]

Citations:


🏁 Script executed:

# Locate and read the Makefile around line 60
find . -name "Makefile" -type f | head -5

Repository: Portabase/portabase

Length of output: 373


🏁 Script executed:

# Search for docker-compose.database.yml
find . -name "docker-compose.database.yml" -type f

Repository: Portabase/portabase

Length of output: 93


🏁 Script executed:

# Read Makefile around line 60 to get full context of e2e-backup target
sed -n '50,75p' ./Makefile

Repository: Portabase/portabase

Length of output: 1200


🏁 Script executed:

# Read docker-compose.database.yml to check for healthcheck definitions
cat ./docker-compose.database.yml

Repository: Portabase/portabase

Length of output: 8650


Add --wait flag to docker compose startup to wait for database services to be healthy.

The docker compose up -d command returns immediately without waiting for service healthchecks to pass. Since the next step runs Playwright tests, this creates a race condition where tests may execute against unstarted or unhealthy database services, causing flaky failures. All services in docker-compose.database.yml define healthchecks, so --wait will properly block until they are ready.

🔧 Proposed fix
-	`@docker` compose -f docker-compose.database.yml up -d
+	`@docker` compose -f docker-compose.database.yml up -d --wait
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@docker compose -f docker-compose.database.yml up -d
`@docker` compose -f docker-compose.database.yml up -d --wait
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 60, Update the Docker Compose startup command used in the
Makefile target that runs "docker compose -f docker-compose.database.yml up -d"
to include the "--wait" flag so the command blocks until services' healthchecks
pass; locate the Makefile target invoking docker compose with "-f
docker-compose.database.yml up -d" and change it to use "docker compose -f
docker-compose.database.yml up --wait -d" (or equivalent ordering) so subsequent
Playwright tests run only after the database services are healthy.

Comment thread Makefile
@echo "Starting backup E2E testing..."
@docker compose -f docker-compose.e2e.yml up -d
@docker compose -f docker-compose.database.yml up -d
@pnpm playwright test --ui || (docker compose -f docker-compose.database.yml down --volumes && docker compose -f docker-compose.e2e.yml down --volumes && exit 1)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Is Playwright --ui mode intended for CI automation, or only for local interactive debugging?

💡 Result:

Playwright UI mode is intended for local interactive development and debugging, not for CI (Continuous Integration) automation [1][2]. Key distinctions include: Purpose and Design: UI mode is specifically designed to provide a better developer experience for active test development [1]. It combines features like watch mode, a time-travel debugging interface, live trace viewing, and a locator picker into a single interactive environment [1][2][3]. It is meant to help developers quickly iterate on tests, inspect the DOM, and debug failures locally [4][2]. CI/CD Compatibility: CI environments are typically headless and automated, designed to run test suites efficiently and report results without human intervention [2][5]. UI mode, conversely, requires a graphical interface and user interaction [4][1]. Official Playwright documentation explicitly recommends UI mode for local debugging and suggests using standard CLI test execution for CI pipelines [2]. Recommended CI Practices: For CI environments, Playwright recommends standard, headless test execution using the CLI (e.g., npx playwright test) [2][5]. To handle debugging in CI, developers should configure features like trace collection (e.g., trace: 'on-first-retry') [6]. These saved trace artifacts can then be opened in the Trace Viewer—a tool separate from UI mode—to perform post-mortem analysis of CI failures without requiring the interactive UI mode during the CI run itself [1][6].

Citations:


🏁 Script executed:

# First, check the Makefile context around line 61
head -70 Makefile | tail -15

Repository: Portabase/portabase

Length of output: 806


🏁 Script executed:

# Look for CI configuration files to understand if this target is used in automation
fd -e yml -e yaml -e json | grep -i -E "ci|github|gitlab|circleci|workflow" | head -20

Repository: Portabase/portabase

Length of output: 45


🏁 Script executed:

# Search for references to this Make target in the codebase
rg "test.*ui|test-e2e" --type makefile -A 2 -B 2

Repository: Portabase/portabase

Length of output: 96


🏁 Script executed:

# Search for CI workflow files
find . -type f \( -name "*.yml" -o -name "*.yaml" -o -name "*.json" \) | grep -i -E "workflow|github|gitlab|ci|action" | head -20

Repository: Portabase/portabase

Length of output: 1428


🏁 Script executed:

# Search the entire Makefile for these targets and any related documentation
cat Makefile | head -100

Repository: Portabase/portabase

Length of output: 3953


🏁 Script executed:

# Look for any documentation about e2e-backup or e2e-manual
rg "e2e-backup|e2e-manual" -i

Repository: Portabase/portabase

Length of output: 105


🏁 Script executed:

# Check the e2e.yml workflow file
cat ./.github/workflows/e2e.yml

Repository: Portabase/portabase

Length of output: 5305


Remove --ui from the e2e-backup Make target.

The --ui flag makes Playwright tests interactive and unsuitable for automated/unattended runs. The target name e2e-backup indicates it should run automatically, and the existing end-to-end target already demonstrates the correct pattern using CI=true and --project=chromium.

🔧 Proposed fix
-	`@pnpm` playwright test --ui || (docker compose -f docker-compose.database.yml down --volumes && docker compose -f docker-compose.e2e.yml down --volumes && exit 1)
+	`@CI`=true pnpm playwright test --project=chromium || (docker compose -f docker-compose.database.yml down --volumes && docker compose -f docker-compose.e2e.yml down --volumes && exit 1)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` at line 61, The e2e-backup Make target currently runs Playwright
with the interactive --ui flag; remove --ui and run Playwright non-interactively
instead by invoking pnpm playwright test with CI=true and the appropriate
project flag (for example CI=true pnpm playwright test --project=chromium) while
keeping the existing error/cleanup chaining (the docker compose down --volumes
&& exit 1 sequence) intact; update the command in the e2e-backup target to use
this non-interactive invocation and ensure no other interactive flags remain.

Comment thread src/lib/logger.ts
const isProd = process.env.NODE_ENV === "production";
const defaultLevel = isProd ? "info" : "debug";
const level = (env.LOG_LEVEL ?? defaultLevel) as pino.Level;
const level = (process.env.LOG_LEVEL ?? defaultLevel) as pino.Level;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether LOG_LEVEL used to be schema-validated and where it's consumed now.
set -euo pipefail

echo "== LOG_LEVEL references =="
rg -n --hidden -C2 '\bLOG_LEVEL\b'

echo
echo "== env schema candidates =="
fd -i 'env.mjs|env.ts|env.js' -t f | xargs -r rg -n -C2 '\bLOG_LEVEL\b|z\.enum|enum'

Repository: Portabase/portabase

Length of output: 3143


🏁 Script executed:

rg -n 'import.*env|from.*env' src/lib/logger.ts src/middleware/loggingMiddleware.ts src/app.ts -A2

Repository: Portabase/portabase

Length of output: 114


🏁 Script executed:

# Check if env is imported anywhere that would run before logger.ts
rg -n 'import.*from.*env.mjs|env.mjs' --hidden -C2

Repository: Portabase/portabase

Length of output: 7395


🏁 Script executed:

# Verify pino.Level type definition to confirm what values it accepts
rg -n 'type.*Level|pino.Level' src/lib/logger.ts -B2 -A2

Repository: Portabase/portabase

Length of output: 276


Use validated env module for LOG_LEVEL instead of direct process.env cast.

src/lib/logger.ts reads process.env.LOG_LEVEL directly and casts to pino.Level without validation. The validated env module in src/env.mjs restricts LOG_LEVEL to ["debug", "info", "warn", "error"], but this validation is bypassed. An invalid LOG_LEVEL can crash logger startup.

Import and use the validated env object from @/env.mjs instead of reading process.env directly. Alternatively, if broader pino levels are intended, expand the env schema to match.

🔧 Proposed fix

Option 1: Use validated env (aligns with current schema):

-import pino from "pino";
+import pino from "pino";
+import { env } from "`@/env.mjs`";

 const isProd = process.env.NODE_ENV === "production";
 const defaultLevel = isProd ? "info" : "debug";
-const level = (process.env.LOG_LEVEL ?? defaultLevel) as pino.Level;
+const level = env.LOG_LEVEL as pino.Level;

Option 2: Validate against all pino levels (requires expanding env schema):

 const isProd = process.env.NODE_ENV === "production";
 const defaultLevel = isProd ? "info" : "debug";
-const level = (process.env.LOG_LEVEL ?? defaultLevel) as pino.Level;
+const allowedLevels: ReadonlySet<pino.Level> = new Set([
+    "fatal", "error", "warn", "info", "debug", "trace", "silent"
+]);
+const requestedLevel = process.env.LOG_LEVEL;
+const level: pino.Level =
+    requestedLevel && allowedLevels.has(requestedLevel as pino.Level)
+        ? (requestedLevel as pino.Level)
+        : defaultLevel;

Also applies to: 24-24

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/logger.ts` at line 5, The logger currently reads
process.env.LOG_LEVEL and casts it to pino.Level via the const level =
(process.env.LOG_LEVEL ?? defaultLevel) as pino.Level; which bypasses validation
and can crash startup; replace this by importing the validated env object from
"`@/env.mjs`" and use env.LOG_LEVEL (falling back to defaultLevel if needed) when
setting level, or alternatively expand the env schema in env.mjs to include all
pino levels and then use env.LOG_LEVEL; update the code that defines level and
any references to ensure they use the validated value (identify the const level,
defaultLevel, and any exports from src/lib/logger.ts to modify).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants