Skip to content

Switching to Octane with Frankenphp#3889

Merged
ildyria merged 1 commit intomasterfrom
frankenphp
Dec 26, 2025
Merged

Switching to Octane with Frankenphp#3889
ildyria merged 1 commit intomasterfrom
frankenphp

Conversation

@ildyria
Copy link
Copy Markdown
Member

@ildyria ildyria commented Dec 26, 2025

Summary by CodeRabbit

  • Chores
    • Added a dockerignore and modernized containerization for a slimmer, production-focused image and consolidated networking so API is the sole public service.
  • New Features
    • Added startup orchestration, environment validation, permissions, admin-user creation, and readiness scripts.
    • CI/CD: added Docker linting, build and vulnerability-scanning jobs.
  • Removed
    • Removed legacy base images, nginx/start scripts, dev image, and legacy cleanup utilities.

✏️ Tip: You can customize this high-level summary in your review settings.

@ildyria ildyria requested a review from a team as a code owner December 26, 2025 11:35
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 26, 2025

📝 Walkthrough

Walkthrough

Replaces legacy Debian/Nginx/PHP-FPM base with a FrankenPHP multi-stage Docker build, adds docker orchestration and validation scripts, restructures docker-compose to an API-centric internal network with hardened services, removes legacy base artifacts, and adds CI jobs for Docker linting, scanning, build, and push.

Changes

Cohort / File(s) Summary
Build context & Dockerfile
\.dockerignore, Dockerfile
Adds .dockerignore. Introduces a multi-stage Dockerfile that installs Composer deps, builds frontend assets with Node, and produces a FrankenPHP (PHP 8.4 Alpine) production image running Laravel Octane on port 8000.
Compose / Services
docker-compose.yaml
Adds public-facing lychee_api; converts lychee_cache and lychee_db to internal-only services (removes host ports), adds healthchecks, resource limits, tmpfs, and capability/security restrictions; removes lychee-dev.
Startup & Validation scripts
docker/scripts/entrypoint.sh, docker/scripts/validate-env.sh, docker/scripts/create-admin-user.sh, docker/scripts/permissions-check.sh
Adds entrypoint (DB readiness, UID/GID handling, migrations, artisan cache/routing/view tasks), environment validation (APP_KEY, DB_* checks, APP_ENV), admin user creation helper, and permissions-checking script.
Removed base & nginx artifacts
docker/base/..., docker/dev/Dockerfile
Deletes legacy Debian-based base Dockerfile, nginx.conf, start.sh, and development Dockerfile contents—removing prior Nginx/PHP-FPM/dev-image layout.
CI / GitHub Actions
.github/workflows/CICD.yml
Adds docker_check and docker-build jobs (hadolint, Trivy, Buildx, GHCR push) and integrates them into CI workflow.
Removed legacy cleanup script
scripts/delete_legacy.sh
Removes legacy cleanup script that deleted legacy app files and edited route/kernel/phpstan configs.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I nibbled at Dockerfiles by moonlight,
Built layers, checked keys, set perms just right.
An API hop, old bases laid to rest,
Healthchecks sing, migrations pass the quest.
A rabbit’s patch — small, tidy, and bright.

Pre-merge checks

✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 88.89% which is sufficient. The required threshold is 80.00%.

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: 11

🧹 Nitpick comments (3)
resources/js/app.ts (1)

39-39: Consider lazy loading for locales.

The current glob pattern eagerly bundles all locale JSON files, which increases the initial bundle size. For applications with many locales, consider lazy loading:

-const langs = import.meta.glob("../../lang/*.json");
+const langs = import.meta.glob("../../lang/*.json", { eager: false });

This would load locales on-demand, reducing the initial bundle size while still supporting dynamic locale switching.

docker/scripts/validate-env.sh (1)

10-15: Consider refactoring to avoid eval for safer code.

While the current implementation is functional and the injection risk is minimal (since variable names are hardcoded), using eval is generally discouraged. Consider using a safer alternative.

🔎 Proposed refactor to avoid eval
 # Check required variables
 for var in $REQUIRED_VARS; do
-    if [ -z "$(eval echo \$$var)" ]; then
+    value=$(env | grep "^${var}=" | cut -d= -f2-)
+    if [ -z "$value" ]; then
         echo "❌ ERROR: Required environment variable $var is not set"
         exit 1
     fi
 done

Alternatively, if you need to support bash:

+#!/bin/bash
-#!/bin/sh
 set -e
 
 # Check required variables
 for var in $REQUIRED_VARS; do
-    if [ -z "$(eval echo \$$var)" ]; then
+    if [ -z "${!var}" ]; then
         echo "❌ ERROR: Required environment variable $var is not set"
         exit 1
     fi
 done
Dockerfile (1)

28-50: Consider running npm audit separately for security checks.

While using npm ci --no-audit speeds up the build, it skips security vulnerability checks. Consider running npm audit as a separate CI/CD step rather than skipping it entirely.

💡 Suggestion

Keep the current build command but add a separate audit step in your CI pipeline:

# In CI/CD pipeline before building
npm audit --production

This ensures security checks without slowing down the Docker build.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f562eb0 and 433f4e9.

📒 Files selected for processing (18)
  • .dockerignore
  • .editorconfig
  • .gitignore
  • Dockerfile
  • app/Http/Kernel.php
  • app/Http/Middleware/SetLocale.php
  • app/Providers/AppServiceProvider.php
  • composer.json
  • docker-compose.yaml
  • docker/base/Dockerfile
  • docker/base/nginx.conf
  • docker/base/start.sh
  • docker/dev/Dockerfile
  • docker/scripts/entrypoint.sh
  • docker/scripts/validate-env.sh
  • package.json
  • resources/js/app.ts
  • resources/js/components/settings/General.vue
💤 Files with no reviewable changes (6)
  • composer.json
  • docker/base/nginx.conf
  • app/Providers/AppServiceProvider.php
  • docker/dev/Dockerfile
  • docker/base/start.sh
  • docker/base/Dockerfile
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{vue,ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{vue,ts,js}: For Vue3/TypeScript frontend code, follow coding conventions defined in docs/specs/3-reference/coding-conventions.md for style, naming, and testing practices.
For frontend changes, run npm run check to ensure all frontend tests pass before committing.

Files:

  • resources/js/app.ts
  • resources/js/components/settings/General.vue
**/*.{vue,ts,js,css}

📄 CodeRabbit inference engine (AGENTS.md)

For frontend changes, run npm run format to apply frontend code formatting with Prettier before committing.

Files:

  • resources/js/app.ts
  • resources/js/components/settings/General.vue
**/*.php

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.php: Any new PHP file should contain the license header and have a single blank line after the opening PHP tag
Variable names should be in snake_case in PHP
Apply the PSR-4 coding standard in PHP
Use in_array() with true as the third parameter in PHP
Only use booleans in if statements, not integers or strings
Use strict comparison (===) instead of loose comparison (==)
Avoid code duplication in both if and else statements
Do not use empty() in PHP
Use the moneyphp/money library for handling monetary values in PHP
Never use floats or doubles to represent monetary values; use integers representing the smallest currency unit (e.g., cents for USD)

**/*.php: Write or extend executable specifications (unit, behaviour, or scenario tests) ahead of implementation, confirm they fail, and then drive code to green before refactoring. List the expected success, validation, and failure branches and add thin failing tests for each path.
For PHP code, adhere to conventions: license headers in new files, strict comparison (===), no empty(), in_array() with third parameter true, snake_case variables, PSR-4 standard, test base classes (AbstractTestCase for Unit, BaseApiWithDataTest for Feature_v2).
Always run phpunit tests. If a test remains red, disable it with a TODO, note the reason, and capture the follow-up in the relevant plan.
Spotless now uses Palantir Java Format 2.78.0 with a 120-character wrap; configure IDE formatters to match before pushing code changes.
Keep each increment's control flow flat by delegating validation/normalisation into tiny pure helpers that return simple enums or result records, then compose them instead of introducing inline branching that inflates the branch count per change.
When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.
For PHP changes, ru...

Files:

  • app/Http/Middleware/SetLocale.php
  • app/Http/Kernel.php
**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.vue: Use TypeScript in composition API for Vue3 and use PrimeVue for UI components
Do not use await async calls in Vue3; use .then() instead
Do not use const function = () => {} syntax; use function functionName() {} instead in Vue3
In Vue3 components, the structure should be first, then <script lang="ts">, then <style>

Files:

  • resources/js/components/settings/General.vue
🧠 Learnings (13)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
📚 Learning: 2025-09-28T08:39:34.280Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3721
File: resources/js/stores/NsfwConsentedState.ts:3-5
Timestamp: 2025-09-28T08:39:34.280Z
Learning: In Lychee codebase, all Pinia store files follow the pattern of declaring the type alias before the store definition (e.g., `export type StoreType = ReturnType<typeof useStore>; export const useStore = defineStore(...)`). This pattern compiles successfully with TypeScript 5.9 and vue-tsc.

Applied to files:

  • resources/js/app.ts
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run vendor/bin/php-cs-fixer fix to apply PHP code style fixes before committing.

Applied to files:

  • .editorconfig
  • .dockerignore
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : Spotless now uses Palantir Java Format 2.78.0 with a 120-character wrap; configure IDE formatters to match before pushing code changes.

Applied to files:

  • .editorconfig
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run make phpstan to verify PHPStan level 6 minimum; fix all errors before committing.

Applied to files:

  • .editorconfig
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run php artisan test to ensure all tests pass before committing.

Applied to files:

  • .editorconfig
  • .dockerignore
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP code, adhere to conventions: license headers in new files, strict comparison (===), no empty(), in_array() with third parameter true, snake_case variables, PSR-4 standard, test base classes (AbstractTestCase for Unit, BaseApiWithDataTest for Feature_v2).

Applied to files:

  • .editorconfig
  • .dockerignore
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.

Applied to files:

  • .editorconfig
📚 Learning: 2025-12-22T14:11:17.217Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T14:11:17.217Z
Learning: Applies to **/*.php : Apply the PSR-4 coding standard in PHP

Applied to files:

  • .editorconfig
📚 Learning: 2025-12-22T14:11:17.217Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-22T14:11:17.217Z
Learning: Applies to **/*.vue : Use TypeScript in composition API for Vue3 and use PrimeVue for UI components

Applied to files:

  • package.json
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.{vue,ts,js,css} : For frontend changes, run npm run format to apply frontend code formatting with Prettier before committing.

Applied to files:

  • package.json
📚 Learning: 2025-11-26T21:50:26.687Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 0
File: :0-0
Timestamp: 2025-11-26T21:50:26.687Z
Learning: In the LycheeOrg/Lychee repository, lang/* files should not be reviewed at all. These files should be completely excluded from code review.

Applied to files:

  • .gitignore
📚 Learning: 2025-12-19T21:01:40.134Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3838
File: lang/pl/webshop.php:1-2
Timestamp: 2025-12-19T21:01:40.134Z
Learning: In the LycheeOrg/Lychee repository, files in the lang/* directory do not require the license header that is normally required for PHP files.

Applied to files:

  • .gitignore
🧬 Code graph analysis (2)
app/Http/Middleware/SetLocale.php (1)
app/Repositories/ConfigManager.php (2)
  • ConfigManager (22-262)
  • getValueAsString (80-83)
app/Http/Kernel.php (1)
app/Http/Middleware/SetLocale.php (1)
  • SetLocale (14-29)
🔇 Additional comments (15)
.gitignore (1)

61-62: LGTM!

The additions appropriately extend gitignore patterns to support the FrankenPHP migration. The case-sensitive variant lychee/* alongside Lychee/* ensures consistent behavior across platforms, and the FrankenPHP-related ignores (frankenphp and frankenphp-worker.php) prevent build artifacts from being committed.

Also applies to: 69-70

resources/js/components/settings/General.vue (2)

253-253: LGTM!

The import of loadLanguageAsync is correctly added to support the new language loading flow.


321-321: RTL language list is correct as-is.

The hardcoded list ["ar", "fa"] accurately covers all RTL languages in the currently supported locales (ar, cz, de, el, en, es, fa, fr, hu, it, ja, nl, no, pl, pt, ru, sk, sv, vi, zh_CN, zh_TW). The suggested languages (Hebrew, Urdu, Yiddish) are not part of the application's supported locales and therefore should not be added to the RTL list.

.editorconfig (2)

28-31: LGTM!

The lang/**.php block configuration is appropriate and consistent with PHP formatting standards.


32-34: LGTM!

The docker-compose.yaml editorconfig block is appropriate with standard 2-space YAML indentation.

package.json (1)

41-41: Moving @lychee-org/leaflet.photo to dependencies is appropriate.

This Leaflet plugin is now correctly categorized as a runtime dependency.

.dockerignore (1)

1-60: LGTM!

The .dockerignore file is comprehensive and well-structured. Key highlights:

  • Correctly excludes development, CI/CD, and test files
  • Preserves .env.example while excluding sensitive .env files
  • Excludes build artifacts (node_modules, storage/logs, cache) appropriately
  • Does not exclude vendor/, which is correct since it's copied from the composer stage
docker/scripts/entrypoint.sh (5)

1-7: LGTM!

The script header and environment validation are properly configured with set -e for fail-fast behavior.


10-32: Database readiness check is well-implemented.

The retry logic with 30 attempts and 2-second intervals provides a reasonable 60-second timeout. The use of nc -z for port checking is appropriate.


34-36: LGTM!

Clearing the bootstrap cache before migrations is good practice to avoid stale configuration issues.


38-40: LGTM!

Running migrations with --force is appropriate for production environments to avoid interactive prompts.


42-52: LGTM!

The Laravel optimization commands are properly ordered, and using exec "$@" ensures the main process replaces the shell, which is essential for proper signal handling in containers.

docker-compose.yaml (2)

236-243: LGTM!

Volume mounts are properly configured with the .env file mounted as read-only for security. The depends_on with health condition ensures proper startup order.


245-253: LGTM!

The healthcheck configuration is well-tuned with appropriate intervals, retries, and start period. The 30-second start period accounts for database migrations during startup.

Dockerfile (1)

86-117: LGTM!

The final production stage is well-structured with:

  • Proper file ownership and permissions for Laravel directories
  • Correct separation of ENTRYPOINT and CMD
  • Appropriate port exposure for Octane

Comment thread app/Http/Kernel.php
Comment thread app/Http/Middleware/SetLocale.php Outdated
Comment thread docker-compose.yaml
Comment thread docker-compose.yaml
Comment thread docker-compose.yaml
Comment thread Dockerfile Outdated
Comment thread Dockerfile Outdated
Comment thread package.json
Comment thread resources/js/app.ts Outdated
Comment thread resources/js/components/settings/General.vue Outdated
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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
database/factories/PhotoFactory.php (1)

80-94: Remove unreachable return statement.

Line 93 contains a return $this; statement that is unreachable because line 92 already returns from the afterCreating callback. This is dead code.

🔎 Proposed fix
 	public function with_palette(): Factory
 	{
 		return $this->afterCreating(function (Photo $photo) {
 			Palette::factory()->with_colour_1(0xFF0000)
 				->with_colour_2(0x00FF00)
 				->with_colour_3(0x0000FF)
 				->with_colour_4(0xFFFF00)
 				->with_colour_5(0xFF00FF)
 				->create(['photo_id' => $photo->id]);
 			$photo->fresh();
 			$photo->load('palette');
 		});
-
-		return $this;
 	}
🧹 Nitpick comments (2)
app/Listeners/CacheListener.php (1)

28-28: LGTM with an optional performance consideration.

The migration to app(ConfigManager::class) is correct for Octane compatibility.

Optional: Since handle() is invoked frequently for cache events, consider injecting ConfigManager as a constructor dependency instead of resolving it per event. This would be more efficient:

🔎 Optional refactor for better performance
 class CacheListener
 {
+	public function __construct(
+		private readonly ConfigManager $config_manager
+	) {
+	}
+
 	/**
 	 * Handle the event.
 	 */
 	public function handle(CacheHit|CacheMissed|KeyForgotten|KeyWritten $event): void
 	{
-		$config_manager = app(ConfigManager::class);
-
 		if (str_contains($event->key, 'lv:dev-lycheeOrg')) {
 			return;
 		}
 
-		if ($config_manager->getValueAsBool('cache_event_logging') === false) {
+		if ($this->config_manager->getValueAsBool('cache_event_logging') === false) {
 			return;
 		}
app/Metadata/Geodecoder.php (1)

39-39: LGTM with an optional refactor suggestion.

The migration to app(ConfigManager::class) is correct for Octane compatibility.

Optional: The three static methods each independently resolve ConfigManager. Since decodeLocation() calls both getGeocoderProvider() and decodeLocation_core(), a single decode operation resolves the manager three times. Consider passing the manager as a parameter to reduce redundant container resolutions:

🔎 Optional refactor to reduce redundant resolutions
 public static function getGeocoderProvider(): ProviderCache
 {
-	$config_manager = app(ConfigManager::class);
+	return self::getGeocoderProviderWithConfig(app(ConfigManager::class));
+}
+
+private static function getGeocoderProviderWithConfig(ConfigManager $config_manager): ProviderCache
+{
 	try {
 		$stack = HandlerStack::create();
 		// ... rest of implementation
 	}
 }

 public static function decodeLocation(?float $latitude, ?float $longitude): ?string
 {
 	$config_manager = app(ConfigManager::class);
 
 	// User does not want to decode location data
 	if (!$config_manager->getValueAsBool('location_decoding')) {
 		return null;
 	}
 	if ($latitude === null || $longitude === null) {
 		return null;
 	}
 
-	$cached_provider = Geodecoder::getGeocoderProvider();
+	$cached_provider = Geodecoder::getGeocoderProviderWithConfig($config_manager);
 
-	return Geodecoder::decodeLocation_core($latitude, $longitude, $cached_provider);
+	return Geodecoder::decodeLocation_core($latitude, $longitude, $cached_provider, $config_manager);
 }

-public static function decodeLocation_core(float $latitude, float $longitude, ProviderCache $cached_provider): ?string
+public static function decodeLocation_core(float $latitude, float $longitude, ProviderCache $cached_provider, ConfigManager $config_manager): ?string
 {
-	$config_manager = app(ConfigManager::class);
-
 	$lang = $config_manager->getValueAsString('lang');
 	// ... rest of implementation
 }

Also applies to: 68-68, 92-92

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 433f4e9 and 205993a.

📒 Files selected for processing (29)
  • app/Http/Middleware/SetLocale.php
  • app/Jobs/ExtractColoursJob.php
  • app/Jobs/ExtractZip.php
  • app/Listeners/CacheListener.php
  • app/Listeners/MetricsListener.php
  • app/Mail/PhotosAdded.php
  • app/Metadata/Geodecoder.php
  • app/Metadata/Json/ChangeLogsRequest.php
  • app/Metadata/Json/CommitsRequest.php
  • app/Metadata/Json/TagsRequest.php
  • app/Metadata/Json/UpdateRequest.php
  • app/Metadata/Versions/InstalledVersion.php
  • composer.json
  • database/factories/AccessPermissionFactory.php
  • database/factories/AlbumFactory.php
  • database/factories/OrderFactory.php
  • database/factories/OrderItemFactory.php
  • database/factories/PaletteFactory.php
  • database/factories/PhotoFactory.php
  • database/factories/PurchasableFactory.php
  • database/factories/PurchasablePriceFactory.php
  • database/factories/RenamerRuleFactory.php
  • database/factories/SizeVariantFactory.php
  • database/factories/StatisticsFactory.php
  • database/factories/TagAlbumFactory.php
  • database/factories/TagFactory.php
  • database/factories/UserFactory.php
  • database/factories/UserGroupFactory.php
  • phpstan.neon
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/Http/Middleware/SetLocale.php
🧰 Additional context used
📓 Path-based instructions (2)
**/*.php

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.php: Any new PHP file should contain the license header and have a single blank line after the opening PHP tag
Variable names should be in snake_case in PHP
Apply the PSR-4 coding standard in PHP
Use in_array() with true as the third parameter in PHP
Only use booleans in if statements, not integers or strings
Use strict comparison (===) instead of loose comparison (==)
Avoid code duplication in both if and else statements
Do not use empty() in PHP
Use the moneyphp/money library for handling monetary values in PHP
Never use floats or doubles to represent monetary values; use integers representing the smallest currency unit (e.g., cents for USD)

**/*.php: Write or extend executable specifications (unit, behaviour, or scenario tests) ahead of implementation, confirm they fail, and then drive code to green before refactoring. List the expected success, validation, and failure branches and add thin failing tests for each path.
For PHP code, adhere to conventions: license headers in new files, strict comparison (===), no empty(), in_array() with third parameter true, snake_case variables, PSR-4 standard, test base classes (AbstractTestCase for Unit, BaseApiWithDataTest for Feature_v2).
Always run phpunit tests. If a test remains red, disable it with a TODO, note the reason, and capture the follow-up in the relevant plan.
Spotless now uses Palantir Java Format 2.78.0 with a 120-character wrap; configure IDE formatters to match before pushing code changes.
Keep each increment's control flow flat by delegating validation/normalisation into tiny pure helpers that return simple enums or result records, then compose them instead of introducing inline branching that inflates the branch count per change.
When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.
For PHP changes, ru...

Files:

  • database/factories/PurchasablePriceFactory.php
  • database/factories/OrderFactory.php
  • database/factories/TagAlbumFactory.php
  • database/factories/PurchasableFactory.php
  • database/factories/AlbumFactory.php
  • app/Mail/PhotosAdded.php
  • app/Metadata/Json/CommitsRequest.php
  • database/factories/PaletteFactory.php
  • app/Jobs/ExtractColoursJob.php
  • app/Metadata/Json/ChangeLogsRequest.php
  • database/factories/SizeVariantFactory.php
  • database/factories/UserGroupFactory.php
  • app/Jobs/ExtractZip.php
  • app/Listeners/MetricsListener.php
  • database/factories/RenamerRuleFactory.php
  • database/factories/StatisticsFactory.php
  • database/factories/UserFactory.php
  • app/Metadata/Json/UpdateRequest.php
  • database/factories/PhotoFactory.php
  • app/Listeners/CacheListener.php
  • app/Metadata/Versions/InstalledVersion.php
  • database/factories/TagFactory.php
  • database/factories/OrderItemFactory.php
  • app/Metadata/Geodecoder.php
  • app/Metadata/Json/TagsRequest.php
  • database/factories/AccessPermissionFactory.php
**/*Request.php

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*Request.php: In Request classes, if a user is provided by the query, place it in $this->user2
In Request classes, reserve $this->user for the user making the request

Files:

  • app/Metadata/Json/CommitsRequest.php
  • app/Metadata/Json/ChangeLogsRequest.php
  • app/Metadata/Json/UpdateRequest.php
  • app/Metadata/Json/TagsRequest.php
🧠 Learnings (4)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.
📚 Learning: 2025-08-14T17:22:19.225Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3618
File: database/factories/TagAlbumFactory.php:53-59
Timestamp: 2025-08-14T17:22:19.225Z
Learning: In TagAlbumFactory (test factory), the user ildyria prefers to keep the simpler loop-based attach() approach over syncWithoutDetaching() optimization since it's only used in tests where N+1 queries and performance are not a concern.

Applied to files:

  • database/factories/TagAlbumFactory.php
📚 Learning: 2025-09-12T20:17:52.985Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3683
File: app/Actions/Shop/CheckoutService.php:216-218
Timestamp: 2025-09-12T20:17:52.985Z
Learning: In the User model (app/Models/User.php), the name attribute uses a getNameAttribute() accessor method that returns a string type. It returns 'Admin' if the username starts with '$2y$' (indicating a hash), otherwise returns the username. This guarantees that $user->name will never be null when $user is not null.

Applied to files:

  • database/factories/UserFactory.php
📚 Learning: 2025-09-12T20:17:52.985Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3683
File: app/Actions/Shop/CheckoutService.php:216-218
Timestamp: 2025-09-12T20:17:52.985Z
Learning: In the User model (app/Models/User.php), the name attribute uses a getNameAttribute() accessor method that returns a string type and falls back to the username if name is null. This guarantees that $user->name will never be null when $user is not null.

Applied to files:

  • database/factories/UserFactory.php
🧬 Code graph analysis (11)
app/Mail/PhotosAdded.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Metadata/Json/CommitsRequest.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Jobs/ExtractColoursJob.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Metadata/Json/ChangeLogsRequest.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Jobs/ExtractZip.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Listeners/MetricsListener.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Metadata/Json/UpdateRequest.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Listeners/CacheListener.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Metadata/Versions/InstalledVersion.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Metadata/Geodecoder.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
app/Metadata/Json/TagsRequest.php (1)
app/Repositories/ConfigManager.php (1)
  • ConfigManager (22-262)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: 3️⃣ PHP dist / 8.4 - mariadb
  • GitHub Check: 3️⃣ PHP dist / 8.5 - sqlite
  • GitHub Check: 3️⃣ PHP dist / 8.4 - sqlite
  • GitHub Check: 3️⃣ PHP dist / 8.5 - postgresql
  • GitHub Check: 2️⃣ PHP tests / 8.5 - mariadb -- Unit
  • GitHub Check: 2️⃣ PHP tests / 8.5 - mariadb -- Feature_v2
  • GitHub Check: 2️⃣ PHP tests / 8.5 - postgresql -- Install
  • GitHub Check: 2️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 2️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 2️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 2️⃣ PHP tests / 8.5 - sqlite -- Install
  • GitHub Check: 2️⃣ PHP tests / 8.5 - mariadb -- Install
  • GitHub Check: 2️⃣ PHP tests / 8.5 - mariadb -- ImageProcessing
  • GitHub Check: 2️⃣ PHP tests / 8.5 - sqlite -- Feature_v2
  • GitHub Check: 2️⃣ PHP tests / 8.5 - postgresql -- Unit
  • GitHub Check: 2️⃣ PHP tests / 8.5 - postgresql -- ImageProcessing
  • GitHub Check: 2️⃣ PHP tests / 8.5 - postgresql -- Webshop
  • GitHub Check: 2️⃣ PHP tests / 8.4 - mariadb -- Install
  • GitHub Check: 2️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
  • GitHub Check: 2️⃣ PHP tests / 8.5 - sqlite -- Unit
🔇 Additional comments (30)
phpstan.neon (1)

16-16: LGTM!

Expanding PHPStan analysis to include database/factories aligns with the factory PHPDoc improvements across the codebase and will help catch type-related issues early.

database/factories/UserGroupFactory.php (1)

16-20: LGTM!

The PHPDoc annotation correctly specifies the factory's model type as class-string<UserGroup>, which will help PHPStan catch type-related issues now that database/factories is included in the analysis paths.

app/Jobs/ExtractZip.php (1)

88-88: LGTM!

The migration to app(ConfigManager::class) is correct. The manager is resolved in handle() and used immediately without being stored in job properties, which properly avoids serialization issues for queued jobs.

app/Jobs/ExtractColoursJob.php (1)

79-79: LGTM!

The migration to app(ConfigManager::class) is correct and follows the established pattern. The manager is resolved in handle() and not stored in job properties, properly avoiding serialization concerns.

app/Metadata/Versions/InstalledVersion.php (1)

68-68: LGTM!

The migration to app(ConfigManager::class) is correct and follows the established DI pattern for Octane compatibility.

app/Mail/PhotosAdded.php (1)

34-36: LGTM. The migration to app(ConfigManager::class) correctly supports Octane compatibility. The constructor immediately extracts the needed string value and discards the manager instance, avoiding serialization issues.

Note: While ConfigManager maintains an internal cache and is not registered as a singleton in production, the usage pattern here is safe because the instance is used only to retrieve a single value and is not stored, eliminating any risk of state leakage between Octane requests.

app/Listeners/MetricsListener.php (1)

25-25: LGTM: Container resolution improves testability.

Switching from direct instantiation to container resolution (app(ConfigManager::class)) is a Laravel best practice that allows for better dependency injection, singleton management, and easier mocking in tests.

composer.json (1)

123-135: LGTM: Proper separation of production and development autoload paths.

Moving Scripts\\, PHPStan\\, and Database\\Factories\\ to autoload-dev correctly restricts these namespaces to development and testing environments, keeping the production autoload lean and focused on the core application.

database/factories/SizeVariantFactory.php (1)

28-28: LGTM: Improved type annotation for static analysis.

The refined docblock @var class-string<SizeVariant> provides better type safety for PHPStan and aligns with the actual usage of SizeVariant::class.

database/factories/TagFactory.php (1)

16-21: LGTM: Added type annotation for model property.

The added docblock with @var class-string<Tag> provides proper type information for static analysis and documents the factory's corresponding model.

database/factories/TagAlbumFactory.php (2)

27-27: LGTM: Improved type annotation for model property.

The refined docblock @var class-string<TagAlbum> provides better type safety for static analysis.


50-50: LGTM: Corrected return type annotation.

Good catch! The return type was incorrectly documented as PhotoFactory but the method actually returns TagAlbumFactory (self). This fix improves documentation accuracy.

app/Metadata/Json/TagsRequest.php (1)

22-22: LGTM: Container resolution follows Laravel best practices.

Resolving ConfigManager via the service container instead of direct instantiation improves testability and aligns with the broader dependency injection pattern adopted across this PR.

database/factories/StatisticsFactory.php (1)

22-22: LGTM: Improved type annotation for static analysis.

The refined docblock @var class-string<Statistics> provides better type safety and aligns with PHPStan analysis requirements.

database/factories/AlbumFactory.php (1)

26-26: LGTM: Improved type annotation for model property.

The refined docblock @var class-string<Album> provides better type safety for static analysis and completes the systematic factory documentation improvements across the codebase.

database/factories/OrderFactory.php (1)

45-45: LGTM! Enhanced type annotation for static analysis.

The PHPDoc refinement from @var string to @var class-string<Order> improves type precision for PHPStan without affecting runtime behavior.

app/Metadata/Json/ChangeLogsRequest.php (1)

22-22: LGTM! Container resolution follows Laravel DI best practices.

Replacing direct instantiation with app(ConfigManager::class) improves testability and aligns with the broader DI refactor across the codebase.

app/Metadata/Json/UpdateRequest.php (1)

22-22: LGTM! Container resolution follows Laravel DI best practices.

The switch to app(ConfigManager::class) improves testability and maintains consistency with similar refactors in ChangeLogsRequest and CommitsRequest.

database/factories/PurchasablePriceFactory.php (1)

25-25: LGTM! Enhanced type annotation for static analysis.

The PHPDoc refinement to @var class-string<PurchasablePrice> improves type precision for PHPStan without runtime impact.

database/factories/UserFactory.php (1)

27-27: LGTM! Enhanced type annotation for static analysis.

The PHPDoc refinement to @var class-string<User> improves type precision for PHPStan without affecting runtime behavior.

database/factories/AccessPermissionFactory.php (1)

26-26: LGTM! Enhanced type annotation for static analysis.

The PHPDoc refinement to @var class-string<AccessPermission> improves type precision for PHPStan without runtime impact.

database/factories/PaletteFactory.php (1)

23-23: LGTM! Enhanced type annotation for static analysis.

The PHPDoc refinement to @var class-string<Palette> improves type precision for PHPStan without affecting runtime behavior.

app/Metadata/Json/CommitsRequest.php (1)

22-22: LGTM! Container resolution follows Laravel DI best practices.

The switch to app(ConfigManager::class) improves testability and maintains consistency with the broader DI refactor pattern across UpdateRequest, ChangeLogsRequest, and other classes.

database/factories/PurchasableFactory.php (1)

26-26: LGTM! Improved type safety.

The PHPDoc refinement to class-string<Purchasable> enhances static analysis and aligns with the factory pattern's type requirements.

database/factories/OrderItemFactory.php (2)

29-29: LGTM! Improved type safety.

The PHPDoc refinement to class-string<OrderItem> enhances static analysis.


95-95: Excellent fix! Corrects invalid instanceof usage.

The change from instanceof string to is_string() fixes a critical bug. The instanceof operator cannot be used with scalar types like string in PHP and would always evaluate to false, causing incorrect behavior.

Also applies to: 118-118

database/factories/PhotoFactory.php (2)

32-32: LGTM! Improved type safety.

The PHPDoc refinement to class-string<Photo> enhances static analysis.


99-99: LGTM! Corrected return type annotations.

The return type annotations now correctly reflect that these methods return PhotoFactory (via self), not array<string,mixed>. This aligns with the fluent interface pattern.

Also applies to: 115-115

database/factories/RenamerRuleFactory.php (2)

16-16: LGTM! Corrected model reference.

The class docblock now correctly references RenamerRule instead of the incorrect Renamer, aligning with the actual model property.


23-23: LGTM! Improved type safety.

The PHPDoc refinement to class-string<RenamerRule> enhances static analysis.

Comment thread database/factories/OrderItemFactory.php Outdated
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: 0

♻️ Duplicate comments (4)
app/Http/Middleware/SetLocale.php (1)

16-28: Return type added, but constructor injection and exception handling still need refinement.

The : mixed return type is a good improvement. However, two recommendations from the previous review remain:

  1. Constructor injection over app() helper: For middleware, Laravel best practice is to inject dependencies via the constructor. This leverages the service container's singleton pattern and makes the dependency explicit.

  2. Overly broad exception catch: Catching \Throwable includes fatal errors and should generally be reserved for top-level handlers. Catching \Exception is more appropriate here.

  3. Silent failure: The caught exception is never logged, making it difficult to debug when locale configuration fails.

🔎 Proposed refactor with constructor DI and improved error handling
+use Illuminate\Support\Facades\Log;
+
 class SetLocale
 {
+	public function __construct(
+		private readonly ConfigManager $configManager
+	) {
+	}
+
 	public function handle(Request $request, \Closure $next): mixed
 	{
 		try {
-			$config_manager = app(ConfigManager::class);
-			$locale = $config_manager->getValueAsString('lang');
-		} catch (\Throwable $e) {
+			$locale = $this->configManager->getValueAsString('lang');
+		} catch (\Exception $e) {
+			Log::warning('Failed to retrieve locale from config', ['error' => $e->getMessage()]);
 			$locale = config('app.locale');
 		}
 
 		app()->setLocale($locale);
 
 		return $next($request);
 	}
 }
docker-compose.yaml (2)

3-16: Avoid using :latest tag for production deployments.

The image tag lychee-frankenphp:latest lacks version pinning, which can lead to unexpected behavior when the image is updated.


255-274: Pin Redis image version and make user ID configurable.

The redis:alpine image tag doesn't specify a version, and user: 1026:100 is hardcoded which may cause permission issues on different host systems.

Dockerfile (1)

58-83: Remove potentially redundant gd package from apk.

The gd package is installed via apk (line 61) and again via install-php-extensions (line 71). The install-php-extensions tool typically handles system library dependencies automatically, so the apk add gd may be redundant.

Additionally, there's inconsistent indentation in this block (tabs on lines 65-66, 73, 78-82 vs spaces elsewhere).

🔎 Suggested fix
 RUN apk add --no-cache \
     exiftool \
     ffmpeg \
-    gd \
     grep \
     imagemagick \
     jpegoptim \
-	netcat-openbsd \
-	unzip \
+    netcat-openbsd \
+    unzip \
     curl \
     && install-php-extensions \
     pdo_mysql \
     pdo_pgsql \
     gd \
     zip \
-	dom \
+    dom \
     bcmath \
     sodium \
     opcache \
     pcntl \
-	exif \
-	imagick \
-	intl \
-	redis \
-	tokenizer \
-	&& rm -rf /var/cache/apk/*
+    exif \
+    imagick \
+    intl \
+    redis \
+    tokenizer \
+    && rm -rf /var/cache/apk/*
🧹 Nitpick comments (2)
docker-compose.yaml (2)

25-25: Consider making APP_FORCE_HTTPS configurable.

This value is hardcoded to "false", but users deploying behind a reverse proxy with TLS termination may need this set to "true".

🔎 Suggested fix
-      APP_FORCE_HTTPS: "false"
+      APP_FORCE_HTTPS: "${APP_FORCE_HTTPS:-false}"

283-287: Validate that required database passwords are set.

The insecure default passwords were removed (improvement from previous review), but if DB_ROOT_PASSWORD or DB_PASSWORD are not set in the environment, MariaDB will receive empty strings which may cause silent failures or security issues.

Consider using the :? syntax to fail fast with a clear error:

🔎 Suggested fix
       environment:
-          - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
+          - MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD:?DB_ROOT_PASSWORD must be set}
           - MYSQL_DATABASE=${DB_DATABASE:-lychee}
           - MYSQL_USER=${DB_USERNAME:-lychee}
-          - MYSQL_PASSWORD=${DB_PASSWORD}
+          - MYSQL_PASSWORD=${DB_PASSWORD:?DB_PASSWORD must be set}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 205993a and 982938e.

📒 Files selected for processing (6)
  • Dockerfile
  • app/Http/Middleware/SetLocale.php
  • database/factories/OrderItemFactory.php
  • docker-compose.yaml
  • resources/js/app.ts
  • resources/js/components/settings/General.vue
🚧 Files skipped from review as they are similar to previous changes (3)
  • resources/js/components/settings/General.vue
  • resources/js/app.ts
  • database/factories/OrderItemFactory.php
🧰 Additional context used
📓 Path-based instructions (1)
**/*.php

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.php: Any new PHP file should contain the license header and have a single blank line after the opening PHP tag
Variable names should be in snake_case in PHP
Apply the PSR-4 coding standard in PHP
Use in_array() with true as the third parameter in PHP
Only use booleans in if statements, not integers or strings
Use strict comparison (===) instead of loose comparison (==)
Avoid code duplication in both if and else statements
Do not use empty() in PHP
Use the moneyphp/money library for handling monetary values in PHP
Never use floats or doubles to represent monetary values; use integers representing the smallest currency unit (e.g., cents for USD)

**/*.php: Write or extend executable specifications (unit, behaviour, or scenario tests) ahead of implementation, confirm they fail, and then drive code to green before refactoring. List the expected success, validation, and failure branches and add thin failing tests for each path.
For PHP code, adhere to conventions: license headers in new files, strict comparison (===), no empty(), in_array() with third parameter true, snake_case variables, PSR-4 standard, test base classes (AbstractTestCase for Unit, BaseApiWithDataTest for Feature_v2).
Always run phpunit tests. If a test remains red, disable it with a TODO, note the reason, and capture the follow-up in the relevant plan.
Spotless now uses Palantir Java Format 2.78.0 with a 120-character wrap; configure IDE formatters to match before pushing code changes.
Keep each increment's control flow flat by delegating validation/normalisation into tiny pure helpers that return simple enums or result records, then compose them instead of introducing inline branching that inflates the branch count per change.
When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.
For PHP changes, ru...

Files:

  • app/Http/Middleware/SetLocale.php
🧠 Learnings (4)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles (as used in Lychee), you may use --ignore-platform-reqs in the composer build stage when generating vendor files, because this stage only affects vendor generation and the final production image is what enforces platform requirements. Ensure: (1) this flag is confined to the build stage and does not affect the production runtime image, (2) the final stage uses the correct platform constraints and installed extensions, and (3) the produced vendor files are compatible with the production image’s PHP/runtime platform. This pattern should be applied to all Dockerfiles that contain a build stage with composer, not just a single file.

Applied to files:

  • Dockerfile
📚 Learning: 2025-08-22T06:11:18.329Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.

Applied to files:

  • Dockerfile
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.

Applied to files:

  • docker-compose.yaml
🧬 Code graph analysis (1)
app/Http/Middleware/SetLocale.php (1)
app/Repositories/ConfigManager.php (2)
  • ConfigManager (22-262)
  • getValueAsString (80-83)
🔇 Additional comments (6)
docker-compose.yaml (2)

241-250: LGTM!

The depends_on with service_healthy condition ensures the database is ready before the API starts, and the healthcheck configuration with appropriate intervals and retries is well-configured.


307-313: LGTM!

Named volumes with explicit names ensure data persistence and easy identification.

Dockerfile (4)

8-23: LGTM!

Using --ignore-platform-reqs in the composer build stage is acceptable since this stage only generates vendor files that are copied to the production image. Based on learnings, the platform requirements that matter are enforced in the final production stage.


28-50: LGTM!

The Node.js build stage follows best practices: using LTS version, npm ci for deterministic installs, and proper layer caching by copying package files before source files.


104-116: LGTM!

Clean separation between entrypoint (for initialization logic) and CMD (for the server process). The Octane configuration with FrankenPHP binding to 0.0.0.0:8000 aligns with the docker-compose port mappings.


88-102: LGTM!

The application copy strategy is sound: copying the application code, then overlaying vendor and built assets from previous stages. The storage and cache directory setup with proper ownership and permissions follows Laravel best practices. The .dockerignore file is properly configured with essential exclusions (.env, .git, node_modules, tests, etc.) to keep the build context clean.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.30%. Comparing base (a772a9e) to head (367dd6d).
⚠️ Report is 1 commits behind head on master.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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: 1

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 982938e and 8e00f8c.

📒 Files selected for processing (1)
  • .github/workflows/CICD.yml
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run vendor/bin/php-cs-fixer fix to apply PHP code style fixes before committing.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.{vue,ts,js} : For frontend changes, run npm run check to ensure all frontend tests pass before committing.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run make phpstan to verify PHPStan level 6 minimum; fix all errors before committing.

Applied to files:

  • .github/workflows/CICD.yml
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: 2️⃣ PHP dist / 8.4 - postgresql
  • GitHub Check: 2️⃣ PHP dist / 8.4 - sqlite
  • GitHub Check: 2️⃣ PHP dist / 8.5 - postgresql
  • GitHub Check: 2️⃣ PHP dist / 8.5 - sqlite
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.4 - postgresql -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Feature_v2
🔇 Additional comments (10)
.github/workflows/CICD.yml (10)

23-25: LGTM! Concurrency control properly configured.

The centralized concurrency configuration with selective cancel-in-progress is well-designed. It will save CI resources by canceling redundant runs on feature branches while protecting master and tag builds.


147-171: LGTM! Dockerfile linting properly configured.

The hadolint action with failure-threshold: warning ensures high-quality Dockerfiles by failing on warnings. The job dependencies on both PHP and JS checks ensure the codebase is validated before Dockerfile validation.


175-180: Docker builds restricted to specific actor and branches.

The condition limits Docker image builds to the 'ildyria' user, master branch, and tags. This means contributor PRs won't build or test Docker images, which could hide Docker-specific issues until after merge.

Consider documenting this restriction and providing guidance for contributors who need to verify Docker builds locally.


203-219: LGTM! Docker tagging strategy is well-designed.

The metadata configuration follows best practices:

  • latest tag only for release tags (prevents master from being tagged as latest)
  • edge tag for master branch builds
  • SHA-based tags for traceability
  • Branch and tag references for clarity

220-230: LGTM! Docker build configuration is appropriate.

The build action correctly:

  • Enables GitHub Actions caching for faster builds
  • Sets production environment for NODE_ENV
  • Uses computed tags and labels from metadata step

236-245: Trivy scan is informational only.

The vulnerability scanner has exit-code: '0', meaning critical/high vulnerabilities will be reported but won't fail the build. This allows releases to proceed even with unfixed security issues.

Consider changing to exit-code: '1' if you want to block releases with critical vulnerabilities, or document this as intentional to avoid blocking on unfixable base image CVEs.


246-254: LGTM! Artifact creation properly depends on frontend checks.

Adding check_js to the dependency list ensures the frontend is validated before building the release artifact. This aligns with best practices for full quality gates.

Based on learnings, this ensures both PHP and frontend changes are validated before creating distribution artifacts.


326-327: LGTM! Release job renumbering is consistent.

The job number update from 5️⃣ to 4️⃣ aligns with the overall workflow stage reorganization while maintaining the correct dependency on createArtifact.


51-53: The referenced reusable workflow file ./.github/workflows/js_check.yml exists and is properly configured. It correctly defines a workflow_call trigger and runs JS checks across multiple Node versions (20 and 22) with appropriate security settings.


231-235: SHA tag extraction pattern is correct.

The jq pattern select(test(":sha-")) correctly matches the format produced by docker/metadata-action v5.10.0 with type=sha. Tags are output as ghcr.io/repo:sha-<commit>, and the pattern correctly filters for the :sha- substring.

Note: With the current configuration (type=sha specified once), only one SHA tag will be produced. If the configuration is modified to include multiple type=sha entries, only the last matching tag would be used. Consider adding error handling if robustness against configuration changes is desired.

Comment thread .github/workflows/CICD.yml Outdated
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: 1

🧹 Nitpick comments (1)
.github/workflows/CICD.yml (1)

33-33: Nice improvement to workflow readability.

The emoji-numbered stages clearly communicate the CI/CD pipeline progression and make it easy to understand job sequencing at a glance.

Also applies to: 60-60, 85-85, 111-111, 138-138, 146-146, 247-247, 327-327

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f53e0dd and c175a10.

📒 Files selected for processing (1)
  • .github/workflows/CICD.yml
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run vendor/bin/php-cs-fixer fix to apply PHP code style fixes before committing.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.{vue,ts,js} : For frontend changes, run npm run check to ensure all frontend tests pass before committing.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run make phpstan to verify PHPStan level 6 minimum; fix all errors before committing.

Applied to files:

  • .github/workflows/CICD.yml
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: 3️⃣ Dockerfile Lint
  • GitHub Check: 2️⃣ PHP dist / 8.4 - postgresql
  • GitHub Check: 2️⃣ PHP dist / 8.5 - mariadb
  • GitHub Check: 2️⃣ PHP dist / 8.5 - sqlite
  • GitHub Check: 2️⃣ PHP dist / 8.4 - mariadb
  • GitHub Check: 2️⃣ PHP dist / 8.5 - postgresql
  • GitHub Check: 2️⃣ PHP dist / 8.4 - sqlite
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
🔇 Additional comments (5)
.github/workflows/CICD.yml (5)

27-29: LGTM! Concurrency configuration is well-designed.

The concurrency group correctly preserves master and tag builds while canceling redundant runs on feature branches and PRs.


55-57: LGTM! JS checks integrated correctly.

The reusable workflow pattern is appropriate and the job runs in parallel with PHP syntax checks for faster feedback.


151-188: LGTM! Docker validation is comprehensive.

The job correctly lints the Dockerfile and scans for vulnerabilities before allowing builds. Running Trivy on a locally built image catches issues early. The configuration appropriately fails on critical/high severity issues while ignoring unfixed vulnerabilities.

Note: This runs on all PRs, which provides good validation but may increase CI time.


220-244: LGTM! Docker metadata and build configuration are correct.

The tagging strategy properly marks master builds as edge and tag builds as latest. GitHub Actions cache integration will speed up repeated builds. The NODE_ENV=production build arg is appropriate for production Docker images.


246-254: LGTM! Artifact job dependencies updated correctly.

Adding check_js to the dependency list ensures frontend validation completes before artifact creation, aligning with the full quality gate approach for changes affecting both backend and frontend.

Comment thread .github/workflows/CICD.yml Outdated
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: 6

🧹 Nitpick comments (5)
app/Actions/Diagnostics/Pipes/Checks/IniSettingsCheck.php (2)

45-48: Enhanced diagnostic output looks good.

The addition of contextual details (current value and recommendation) significantly improves the diagnostic user experience.

Optional: Remove unnecessary parentheses

Line 45 has an extra pair of parentheses around '30M':

-		if (Helpers::convertSize(ini_get('upload_max_filesize')) < Helpers::convertSize(('30M'))) {
+		if (Helpers::convertSize(ini_get('upload_max_filesize')) < Helpers::convertSize('30M')) {

49-52: Enhanced diagnostic output looks good.

The addition of contextual details (current value and recommendation) improves the diagnostic output.

Optional: Remove unnecessary parentheses

Line 49 has an extra pair of parentheses around '100M':

-		if (Helpers::convertSize(ini_get('post_max_size')) < Helpers::convertSize(('100M'))) {
+		if (Helpers::convertSize(ini_get('post_max_size')) < Helpers::convertSize('100M')) {
docker-compose.yaml (1)

289-291: Consider pinning Redis image version.

The redis:alpine tag doesn't specify a version, which can lead to unexpected behavior when Alpine or Redis updates. A previous review recommended redis:7-alpine for reproducibility.

🔎 Recommended fix
   lychee_cache:
-      image: redis:alpine
+      image: redis:7-alpine
docker/scripts/permissions-check.sh (1)

19-22: Consider error handling for required directories.

Lines 19-20 will fail with set -e if /app/storage or /app/bootstrap/cache don't exist (e.g., during initial container setup), while lines 21-22 correctly suppress errors for optional paths. You may want consistent error handling or ensure these directories are created in the Dockerfile.

docker/scripts/validate-env.sh (1)

10-16: Variable expansion approach is safe but could be cleaner.

The eval echo "\${$var:-}" pattern works safely here since REQUIRED_VARS is hardcoded. However, a cleaner POSIX-compatible approach would use printenv:

🔎 Alternative approach
 for var in $REQUIRED_VARS; do
-    val=$(eval echo "\${$var:-}")
+    val=$(printenv "$var" 2>/dev/null || true)
     if [ -z "$val" ]; then
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c175a10 and e141b2f.

📒 Files selected for processing (11)
  • .github/workflows/CICD.yml
  • Dockerfile
  • app/Actions/Diagnostics/Pipes/Checks/DBSupportCheck.php
  • app/Actions/Diagnostics/Pipes/Checks/IniSettingsCheck.php
  • app/Actions/Diagnostics/Pipes/Infos/DockerVersionInfo.php
  • config/features.php
  • docker-compose.yaml
  • docker/scripts/create-admin-user.sh
  • docker/scripts/entrypoint.sh
  • docker/scripts/permissions-check.sh
  • docker/scripts/validate-env.sh
💤 Files with no reviewable changes (1)
  • app/Actions/Diagnostics/Pipes/Checks/DBSupportCheck.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • Dockerfile
🧰 Additional context used
📓 Path-based instructions (1)
**/*.php

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.php: Any new PHP file should contain the license header and have a single blank line after the opening PHP tag
Variable names should be in snake_case in PHP
Apply the PSR-4 coding standard in PHP
Use in_array() with true as the third parameter in PHP
Only use booleans in if statements, not integers or strings
Use strict comparison (===) instead of loose comparison (==)
Avoid code duplication in both if and else statements
Do not use empty() in PHP
Use the moneyphp/money library for handling monetary values in PHP
Never use floats or doubles to represent monetary values; use integers representing the smallest currency unit (e.g., cents for USD)

**/*.php: Write or extend executable specifications (unit, behaviour, or scenario tests) ahead of implementation, confirm they fail, and then drive code to green before refactoring. List the expected success, validation, and failure branches and add thin failing tests for each path.
For PHP code, adhere to conventions: license headers in new files, strict comparison (===), no empty(), in_array() with third parameter true, snake_case variables, PSR-4 standard, test base classes (AbstractTestCase for Unit, BaseApiWithDataTest for Feature_v2).
Always run phpunit tests. If a test remains red, disable it with a TODO, note the reason, and capture the follow-up in the relevant plan.
Spotless now uses Palantir Java Format 2.78.0 with a 120-character wrap; configure IDE formatters to match before pushing code changes.
Keep each increment's control flow flat by delegating validation/normalisation into tiny pure helpers that return simple enums or result records, then compose them instead of introducing inline branching that inflates the branch count per change.
When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.
For PHP changes, ru...

Files:

  • config/features.php
  • app/Actions/Diagnostics/Pipes/Checks/IniSettingsCheck.php
  • app/Actions/Diagnostics/Pipes/Infos/DockerVersionInfo.php
🧠 Learnings (7)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run vendor/bin/php-cs-fixer fix to apply PHP code style fixes before committing.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.{vue,ts,js} : For frontend changes, run npm run check to ensure all frontend tests pass before committing.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : When introducing new helpers/utilities or editing files prone to style violations (records, DTOs, generated adapters), run the narrowest applicable lint target (for example phpstan) before the full pipeline. Note the command in the related plan/task.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: Applies to **/*.php : For PHP changes, run make phpstan to verify PHPStan level 6 minimum; fix all errors before committing.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.

Applied to files:

  • docker-compose.yaml
🧬 Code graph analysis (1)
app/Actions/Diagnostics/Pipes/Checks/IniSettingsCheck.php (2)
app/DTO/DiagnosticData.php (2)
  • DiagnosticData (13-72)
  • warn (54-57)
app/Assets/Helpers.php (2)
  • Helpers (20-296)
  • convertSize (149-167)
🪛 Shellcheck (0.11.0)
docker/scripts/create-admin-user.sh

[warning] 2-2: In POSIX sh, set option pipefail is undefined.

(SC3040)

docker/scripts/validate-env.sh

[warning] 2-2: In POSIX sh, set option pipefail is undefined.

(SC3040)

docker/scripts/permissions-check.sh

[warning] 2-2: In POSIX sh, set option pipefail is undefined.

(SC3040)

docker/scripts/entrypoint.sh

[warning] 2-2: In POSIX sh, set option pipefail is undefined.

(SC3040)

⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: 2️⃣ PHP dist / 8.4 - mariadb
  • GitHub Check: 1️⃣ PHP tests / 8.4 - postgresql -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.4 - mariadb -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Install
🔇 Additional comments (9)
app/Actions/Diagnostics/Pipes/Checks/IniSettingsCheck.php (1)

53-59: LGTM! Enhanced diagnostic details provide clear guidance.

The addition of current value and dual recommendations (200 seconds or 0 for no limit) gives users actionable information to resolve the issue.

app/Actions/Diagnostics/Pipes/Infos/DockerVersionInfo.php (1)

78-87: LGTM!

The new isLycheeFrankenPHP() method follows the established pattern of the existing Docker detection methods. The marker file /frankenphp_target provides a clean way to identify the FrankenPHP-based image, and the match expression ordering is correct.

.github/workflows/CICD.yml (2)

189-194: Docker build job dependency chain verified.

The docker-build job correctly depends on docker_check (line 196), ensuring the Dockerfile is linted and the image passes vulnerability scanning before being pushed to the registry. The conditional logic is now correct.


246-253: Job dependency graph is well-structured.

The createArtifact job correctly includes check_js in its dependencies, ensuring frontend checks complete before artifact creation. The parallel execution of createArtifact (artifact build) and docker-build (Docker image push) after their respective gates is an efficient design.

docker-compose.yaml (1)

337-341: Verify database passwords are provided via .env file.

MariaDB requires MYSQL_ROOT_PASSWORD (or MYSQL_ALLOW_EMPTY_PASSWORD=yes) to start. With the inline password variables commented out, ensure your .env file provides DB_ROOT_PASSWORD and DB_PASSWORD, or the container will fail to initialize.

docker/scripts/create-admin-user.sh (1)

25-30: Good security hygiene.

The script appropriately clears sensitive variables after use and prefers reading passwords from files over environment variables. The password length validation adds an extra layer of protection.

docker/scripts/entrypoint.sh (2)

66-75: Laravel bootstrap sequence is correct.

The optimization sequence properly clears bootstrap cache first, runs migrations with --force for non-interactive mode, then caches configuration, routes, and views. This is the recommended order for production deployments.


16-21: No action needed. The nc command is explicitly installed via netcat-openbsd in the Dockerfile (line 72) as part of the production image build, so the database readiness check will work as intended without requiring a fallback.

Likely an incorrect or invalid review comment.

docker/scripts/validate-env.sh (1)

18-23: Good APP_KEY format validation.

Validating that the APP_KEY matches Laravel's expected base64:... format with sufficient length is a solid security check. The helpful error message with the generation command is a nice touch for developers.

Comment thread config/features.php
Comment thread docker-compose.yaml Outdated
Comment thread docker/scripts/create-admin-user.sh
Comment thread docker/scripts/entrypoint.sh
Comment thread docker/scripts/permissions-check.sh
Comment thread docker/scripts/validate-env.sh
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: 2

♻️ Duplicate comments (3)
docker/scripts/create-admin-user.sh (1)

1-35: LGTM - Security-conscious admin user creation.

The script handles sensitive data appropriately by preferring file-based secrets over environment variables, enforcing minimum password length, and clearing sensitive variables after use. The shellcheck disable directive on line 2 explicitly acknowledges the pipefail compatibility concern flagged in past reviews.

Dockerfile (1)

64-91: Remove duplicate gd extension installation.

The gd extension is installed via both apk (line 68) and install-php-extensions (line 78), causing unnecessary build overhead.

🔎 Proposed fix
 RUN apk add --no-cache \
     exiftool \
 	shadow \
     ffmpeg \
-    gd \
     grep \
     imagemagick \
docker-compose.yaml (1)

289-289: Pin Redis image to a specific version.

Using redis:alpine without version pinning can lead to unexpected updates and breaking changes. This issue was flagged in previous reviews but remains unresolved.

🔎 Recommended fix
-      image: redis:alpine
+      image: redis:7-alpine  # Pin to Redis 7.x
🧹 Nitpick comments (1)
docker/scripts/entrypoint.sh (1)

10-33: Consider adding defensive validation for DB_HOST and DB_PORT.

While validate-env.sh likely checks these variables, adding a defensive check here before using them in the nc command would provide clearer error messages and fail-fast behavior.

🔎 Proposed enhancement
 # Wait for database to be ready
 if [ "${DB_CONNECTION:-}" = "mysql" ] || [ "${DB_CONNECTION:-}" = "pgsql" ]; then
+    if [ -z "${DB_HOST:-}" ] || [ -z "${DB_PORT:-}" ]; then
+        echo "❌ ERROR: DB_HOST and DB_PORT must be set for ${DB_CONNECTION}"
+        exit 1
+    fi
+
     echo "⏳ Waiting for database to be ready..."
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e141b2f and be623c3.

📒 Files selected for processing (7)
  • Dockerfile
  • docker-compose.yaml
  • docker/scripts/create-admin-user.sh
  • docker/scripts/entrypoint.sh
  • docker/scripts/permissions-check.sh
  • docker/scripts/validate-env.sh
  • scripts/delete_legacy.sh
💤 Files with no reviewable changes (1)
  • scripts/delete_legacy.sh
🚧 Files skipped from review as they are similar to previous changes (2)
  • docker/scripts/validate-env.sh
  • docker/scripts/permissions-check.sh
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles (as used in Lychee), you may use --ignore-platform-reqs in the composer build stage when generating vendor files, because this stage only affects vendor generation and the final production image is what enforces platform requirements. Ensure: (1) this flag is confined to the build stage and does not affect the production runtime image, (2) the final stage uses the correct platform constraints and installed extensions, and (3) the produced vendor files are compatible with the production image’s PHP/runtime platform. This pattern should be applied to all Dockerfiles that contain a build stage with composer, not just a single file.

Applied to files:

  • Dockerfile
📚 Learning: 2025-08-22T06:11:18.329Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.

Applied to files:

  • Dockerfile
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.

Applied to files:

  • docker-compose.yaml
🔇 Additional comments (3)
Dockerfile (1)

128-141: LGTM - Proper script and entrypoint configuration.

The startup scripts are correctly copied with appropriate permissions, and the entrypoint/CMD configuration properly orchestrates the container startup with Laravel Octane and FrankenPHP.

docker/scripts/entrypoint.sh (1)

35-59: LGTM - Robust UID/GID management with security validation.

The PUID/PGID validation enforces safe ranges (preventing root and system IDs), and the conditional user modification appropriately handles environments where the shadow package is unavailable.

docker-compose.yaml (1)

336-341: LGTM - Secure credential handling.

Database passwords are appropriately required from the .env file rather than having insecure defaults. The commented lines for MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD (lines 337, 340) ensure credentials must be explicitly provided.

Comment thread docker-compose.yaml Outdated
Comment thread docker-compose.yaml
Base automatically changed from refactor-for-speed to webshop/backend-end December 26, 2025 17:56
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

♻️ Duplicate comments (6)
docker/scripts/create-admin-user.sh (1)

1-3: Pipefail shell compatibility addressed.

The shellcheck disable directive on line 2 acknowledges the POSIX sh incompatibility. This is an acceptable resolution as long as the target container includes a shell that supports pipefail (busybox ash in Alpine does support it).

docker/scripts/permissions-check.sh (1)

1-3: Pipefail shell compatibility addressed.

Same as create-admin-user.sh—the shellcheck disable directive acknowledges the POSIX incompatibility and is acceptable.

docker/scripts/entrypoint.sh (1)

1-3: Pipefail shell compatibility addressed.

Same resolution as the other scripts—acceptable with shellcheck disable directive.

Dockerfile (1)

64-91: Remove duplicate gd extension installation.

The gd extension is installed via both apk (line 68) and install-php-extensions (line 78). Remove the apk version to avoid redundancy and reduce build time.

🔎 Proposed fix
 RUN apk add --no-cache \
     exiftool \
 	shadow \
     ffmpeg \
-    gd \
     grep \
     imagemagick \
     jpegoptim \
docker-compose.yaml (2)

288-316: Pin Redis version and make user ID configurable.

Line 289 uses redis:alpine without a version pin, which can lead to unexpected updates. Line 306 hardcodes user: 999:999 with a comment claiming this is the redis user in Alpine, but this may not be consistent across all Alpine versions or Redis images.

🔎 Proposed fix
   lychee_cache:
-      image: redis:alpine
+      image: redis:7-alpine  # Pin to specific Redis major version
       hostname: lychee_cache
       security_opt:
           - no-new-privileges:true
       cap_drop:
           - ALL
       cap_add:
           - SETGID
           - SETUID
       read_only: true
       tmpfs:
           - /tmp:noexec,nosuid,nodev,size=50m
       healthcheck:
           test: ["CMD-SHELL", "redis-cli ping || exit 1"]
       # Removed port exposure - only accessible within Docker network
       # ports:
       #     - ${REDIS_PORT:-6379}:${REDIS_PORT:-6379}
-      user: 999:999  # redis user in Alpine
+      user: "${REDIS_USER_ID:-999}:${REDIS_GROUP_ID:-999}"  # redis user in Alpine

46-48: Align PUID/PGID defaults with entrypoint.sh and www-data.

Lines 47-48 default PUID and PGID to 1000, but entrypoint.sh defaults them to 33 (matching www-data in Alpine). The docker-compose values override the entrypoint defaults, potentially causing permission mismatches since the application expects www-data (33:33). Consider aligning both to 33 for consistency, or document why 1000 is preferred for Docker Compose deployments.

🔎 Proposed fix for consistency
     environment:
-      PUID: "${PUID:-1000}"
-      PGID: "${PGID:-1000}"
+      PUID: "${PUID:-33}"
+      PGID: "${PGID:-33}"
🧹 Nitpick comments (4)
docker/scripts/entrypoint.sh (2)

35-47: Add numeric validation for PUID/PGID.

Lines 40-47 perform numeric range comparisons on PUID and PGID without first validating they contain numeric values. If a user provides non-numeric values, the script may fail with unclear errors.

🔎 Proposed fix
 echo "Validating and setting PUID/PGID"
 PUID=${PUID:-33}
 PGID=${PGID:-33}
 
+# Validate PUID/PGID are numeric
+if ! printf '%s' "$PUID" | grep -qE '^[0-9]+$'; then
+    echo "❌ ERROR: PUID must be numeric (got: $PUID)"
+    exit 1
+fi
+if ! printf '%s' "$PGID" | grep -qE '^[0-9]+$'; then
+    echo "❌ ERROR: PGID must be numeric (got: $PGID)"
+    exit 1
+fi
+
 # Validate PUID/PGID are within safe ranges (no root, within system limits)
 if [ "$PUID" -lt 33 ] || [ "$PUID" -gt 65534 ]; then

67-76: Laravel artisan commands protected by set -e.

The artisan commands (migrate, config:cache, etc.) will cause the script to exit on failure due to set -e on line 3. However, for improved error visibility, consider adding explicit error checks with descriptive messages.

🔎 Example: explicit error handling
 # Run database migrations
 echo "🔄 Running database migrations..."
-php artisan migrate --force
+if ! php artisan migrate --force; then
+    echo "❌ ERROR: Database migration failed"
+    exit 1
+fi
.github/workflows/CICD.yml (1)

176-177: Pass NODE_ENV consistently in both docker jobs.

Line 177 builds the Docker image without specifying NODE_ENV, relying on the Dockerfile's default. For consistency with the docker-build job (line 243-244) and explicitness, consider passing --build-arg NODE_ENV=production here as well.

🔎 Proposed fix
       - name: Build Docker image locally
-        run: docker build -t lychee:local .
+        run: docker build --build-arg NODE_ENV=production -t lychee:local .
docker-compose.yaml (1)

318-358: Consider more specific MariaDB version pin.

Line 319 uses mariadb:10, which pins the major version but allows minor version updates. For maximum reproducibility, consider pinning to a specific minor version (e.g., mariadb:10.11). The security hardening (capabilities, tmpfs, healthcheck) and password handling via .env are well-implemented.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be623c3 and a1124ff.

📒 Files selected for processing (12)
  • .dockerignore
  • .github/workflows/CICD.yml
  • Dockerfile
  • docker-compose.yaml
  • docker/base/Dockerfile
  • docker/base/nginx.conf
  • docker/base/start.sh
  • docker/dev/Dockerfile
  • docker/scripts/create-admin-user.sh
  • docker/scripts/entrypoint.sh
  • docker/scripts/permissions-check.sh
  • docker/scripts/validate-env.sh
💤 Files with no reviewable changes (4)
  • docker/base/nginx.conf
  • docker/base/Dockerfile
  • docker/base/start.sh
  • docker/dev/Dockerfile
🚧 Files skipped from review as they are similar to previous changes (2)
  • .dockerignore
  • docker/scripts/validate-env.sh
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.

Applied to files:

  • docker-compose.yaml
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles (as used in Lychee), you may use --ignore-platform-reqs in the composer build stage when generating vendor files, because this stage only affects vendor generation and the final production image is what enforces platform requirements. Ensure: (1) this flag is confined to the build stage and does not affect the production runtime image, (2) the final stage uses the correct platform constraints and installed extensions, and (3) the produced vendor files are compatible with the production image’s PHP/runtime platform. This pattern should be applied to all Dockerfiles that contain a build stage with composer, not just a single file.

Applied to files:

  • Dockerfile
📚 Learning: 2025-08-22T06:11:18.329Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.

Applied to files:

  • Dockerfile
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.

Applied to files:

  • .github/workflows/CICD.yml
🔇 Additional comments (4)
docker/scripts/permissions-check.sh (1)

20-23: Inconsistent error handling is intentional for optional directories.

Lines 20-21 enforce ownership on required directories (/app/storage, /app/bootstrap/cache) without error suppression, ensuring they exist. Lines 22-23 suppress errors for optional directories (/app/public/uploads, /app/public/dist) that may not exist initially. This pattern is correct given the directory requirements.

Dockerfile (1)

105-125: LGTM: Good security and operational practices.

The directory setup, placeholder file creation, use of php.ini-production, and custom PHP settings (upload limits, execution time, security headers) all follow best practices for production Laravel deployments.

.github/workflows/CICD.yml (1)

189-245: LGTM: Docker build and push job is well-configured.

The job correctly uses conditional push logic, authenticated registry login, metadata extraction for tags, and build cache optimization. The explicit NODE_ENV=production build arg ensures consistent production builds.

docker-compose.yaml (1)

4-16: Clarify image versioning strategy for lychee_api.

Line 5 uses lychee-frankenphp:latest, which was previously flagged and marked as addressed. If this docker-compose.yaml is intended for local development, the :latest tag is acceptable. However, for production deployments, use explicit version tags. Consider documenting the intended use case or providing a production-specific compose file with pinned versions.

Comment thread docker/scripts/create-admin-user.sh
Comment thread docker/scripts/create-admin-user.sh
Comment thread docker/scripts/entrypoint.sh
Base automatically changed from webshop/backend-end to master December 26, 2025 20:32
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: 1

♻️ Duplicate comments (4)
Dockerfile (1)

64-91: Remove duplicate gd extension installation.

The gd extension is installed via both apk (line 68) and install-php-extensions (line 78). This redundancy increases build time unnecessarily.

🔎 Proposed fix
 RUN apk add --no-cache \
     exiftool \
 	shadow \
     ffmpeg \
-    gd \
     grep \
     imagemagick \
     jpegoptim \
 	netcat-openbsd \
 	unzip \
     curl \
     && install-php-extensions \
     pdo_mysql \
     pdo_pgsql \
     gd \
     zip \
 	dom \
     bcmath \
     sodium \
     opcache \
     pcntl \
 	exif \
 	imagick \
 	intl \
 	redis \
 	tokenizer \
 	&& rm -rf /var/cache/apk/* \
 	&& apk del shadow
docker/scripts/create-admin-user.sh (2)

9-16: Validate file readability before reading password.

The script should verify ADMIN_PASSWORD_FILE is readable before attempting to read it to provide clearer error messages.

🔎 Proposed fix
   # Prefer reading from file (more secure than env var)
   if [ -n "${ADMIN_PASSWORD_FILE:-}" ] && [ -f "${ADMIN_PASSWORD_FILE}" ]; then
-    # Securely read password file (no command substitution vulnerabilities)
-    value=$(cat "${ADMIN_PASSWORD_FILE}")
+    if [ -r "${ADMIN_PASSWORD_FILE}" ]; then
+      value=$(cat "${ADMIN_PASSWORD_FILE}")
+    else
+      echo "❌ ERROR: ADMIN_PASSWORD_FILE exists but is not readable"
+      exit 1
+    fi
   elif [ -n "${ADMIN_PASSWORD:-}" ]; then

26-27: Verify admin user creation succeeds.

The php artisan lychee:create_user command should have its exit code checked. If user creation fails, the script should exit with an error rather than silently continuing.

🔎 Proposed fix
     echo "🚀 Creating admin account for user: ${ADMIN_USER}"
-    php artisan lychee:create_user "${ADMIN_USER}" "${value}"
+    if ! php artisan lychee:create_user "${ADMIN_USER}" "${value}"; then
+      echo "❌ ERROR: Failed to create admin user"
+      exit 1
+    fi
docker/scripts/entrypoint.sh (1)

10-33: Add DB_PORT validation to validate-env.sh.

Line 18 uses ${DB_PORT} without validation. The validate-env.sh script validates DB_HOST, DB_DATABASE, and DB_USERNAME for mysql/pgsql connections, but does not validate DB_PORT. When DB_PORT is unset, the nc command will fail with an unclear error.

The validation should be added to docker/scripts/validate-env.sh in the conditional block that checks database credentials for mysql/pgsql connections.

🧹 Nitpick comments (1)
docker-compose.yaml (1)

288-316: Pin Redis image version for reproducibility.

The redis:alpine image tag doesn't specify a version, which can lead to unexpected updates. For production deployments, specify an explicit version tag.

🔎 Recommended fix
   lychee_cache:
-      image: redis:alpine
+      image: redis:7-alpine  # Pin to specific Redis version
       hostname: lychee_cache
       security_opt:
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1124ff and 367dd6d.

📒 Files selected for processing (12)
  • .dockerignore
  • .github/workflows/CICD.yml
  • Dockerfile
  • docker-compose.yaml
  • docker/base/Dockerfile
  • docker/base/nginx.conf
  • docker/base/start.sh
  • docker/dev/Dockerfile
  • docker/scripts/create-admin-user.sh
  • docker/scripts/entrypoint.sh
  • docker/scripts/permissions-check.sh
  • docker/scripts/validate-env.sh
💤 Files with no reviewable changes (4)
  • docker/base/start.sh
  • docker/base/nginx.conf
  • docker/dev/Dockerfile
  • docker/base/Dockerfile
🚧 Files skipped from review as they are similar to previous changes (2)
  • .dockerignore
  • docker/scripts/permissions-check.sh
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.
📚 Learning: 2025-12-22T14:12:18.082Z
Learnt from: CR
Repo: LycheeOrg/Lychee PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-22T14:12:18.082Z
Learning: When both PHP and frontend files are modified, run the full quality gate: vendor/bin/php-cs-fixer fix, npm run format, npm run check, php artisan test, and make phpstan.

Applied to files:

  • .github/workflows/CICD.yml
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles for the Lychee project, using `--ignore-platform-reqs` in the composer build stage is acceptable because it's only used to generate vendor files that are copied to the production stage. The platform requirements that matter are in the final production image, not the intermediate build stage.

Applied to files:

  • docker-compose.yaml
📚 Learning: 2025-12-26T11:45:18.032Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3889
File: Dockerfile:8-23
Timestamp: 2025-12-26T11:45:18.032Z
Learning: In multi-stage Dockerfiles (as used in Lychee), you may use --ignore-platform-reqs in the composer build stage when generating vendor files, because this stage only affects vendor generation and the final production image is what enforces platform requirements. Ensure: (1) this flag is confined to the build stage and does not affect the production runtime image, (2) the final stage uses the correct platform constraints and installed extensions, and (3) the produced vendor files are compatible with the production image’s PHP/runtime platform. This pattern should be applied to all Dockerfiles that contain a build stage with composer, not just a single file.

Applied to files:

  • Dockerfile
📚 Learning: 2025-08-22T06:11:18.329Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3641
File: lang/no/settings.php:9-9
Timestamp: 2025-08-22T06:11:18.329Z
Learning: For lang/* translation files in the Lychee project: only review PHP-related issues (syntax, structure, etc.), not translation content, grammar, or language-related nitpicks. The maintainer ildyria has explicitly requested this approach.

Applied to files:

  • Dockerfile
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: 1️⃣ PHP 8.4 - Code Style errors
  • GitHub Check: 1️⃣ PHP 8.4 - License Check
🔇 Additional comments (2)
.github/workflows/CICD.yml (2)

151-188: LGTM! Well-structured Docker validation job.

The docker_check job properly validates the Dockerfile with Hadolint, builds locally, and scans with Trivy. The dependency on phpstan and check_js ensures code quality before Docker validation.


189-245: LGTM! Docker build and push job is correctly configured.

The job properly:

  • Conditionally runs only on master/tags
  • Uses security hardening
  • Authenticates to GHCR
  • Leverages build cache
  • Passes necessary build arguments

Comment thread docker/scripts/validate-env.sh
@ildyria ildyria merged commit 77c6135 into master Dec 26, 2025
59 of 73 checks passed
@ildyria ildyria deleted the frankenphp branch December 26, 2025 22:33
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.

1 participant