Skip to content

Conversation

@ildyria
Copy link
Member

@ildyria ildyria commented Jan 4, 2026

Summary by CodeRabbit

  • New Features

    • Admin-configurable default album view (grid or list) exposed to the app; users can toggle between grid/list from header and album hero. List view shows counts on wide screens, respects NSFW visibility, and adds RTL/accessibility improvements.
  • Bug Fixes

    • Improved album date parsing by trimming titles to avoid whitespace issues.
  • Documentation

    • Specs and roadmap updated to reflect implementation, testing, and UX details.

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

@ildyria ildyria requested a review from a team as a code owner January 4, 2026 13:59
@coderabbitai
Copy link

coderabbitai bot commented Jan 4, 2026

📝 Walkthrough

Walkthrough

Adds admin-configurable album layout (enum + migration), exposes album_layout via InitConfig to the frontend, initializes LycheeState.album_view_mode, implements list-view Vue components and toggles, updates docs/specs, trims album titles before date parsing, removes final from two metadata classes, and adds unit tests.

Changes

Cohort / File(s) Summary
Backend enum & config
app/Enum/AlbumLayoutType.php, database/migrations/2026_01_04_000000_add_album_layout_config.php, app/Http/Resources/GalleryConfigs/InitConfig.php
New AlbumLayoutType enum (LIST, GRID); migration adding album_layout config (default grid, type range `grid
Frontend types & state
resources/js/lychee.d.ts, resources/js/stores/LycheeState.ts, resources/js/stores/CatalogState.ts
Adds App.Enum.AlbumLayoutType and InitConfig.album_layout typings; introduces LycheeState.album_view_mode (default "grid") and loads it from InitConfig; tightens CatalogState.load() early-exit for short albumId.
New list-view components & UI integration
resources/js/components/gallery/albumModule/AlbumListView.vue, resources/js/components/gallery/albumModule/AlbumListItem.vue, resources/js/components/gallery/albumModule/thumbs/ListBadge.vue, resources/js/components/gallery/albumModule/AlbumThumbPanel.vue, resources/js/components/gallery/albumModule/AlbumHero.vue, resources/js/components/headers/AlbumsHeader.vue, resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
Adds AlbumListView, AlbumListItem, and ListBadge components; integrates list/grid conditional rendering in AlbumThumbPanel; adds toggle controls in AlbumHero and AlbumsHeader updating album_view_mode; makes drag-aware thumbnail rendering tweaks.
Minor backend code & tests
app/Http/Resources/Models/Utils/TimelineData.php, app/Metadata/Versions/Remote/GitCommits.php, app/Metadata/Versions/Remote/GitTags.php, tests/Unit/Metadata/GitHubVersionTest.php
TimelineData::fromAlbum trims album titles before date parsing; removed final from GitCommits and GitTags classes; new unit test GitHubVersionTest.php added exercising version/remote logic.
Docs, spec & roadmap
docs/specs/4-architecture/features/005-album-list-view/plan.md, docs/specs/4-architecture/features/005-album-list-view/spec.md, docs/specs/4-architecture/features/005-album-list-view/tasks.md, docs/specs/4-architecture/roadmap.md
Updates status to Ready, expanded vision/scope and implementation plan, enumerates frontend components and tests, and moves feature to Completed in roadmap.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I hopped from enum to migration line,
Tucked defaults where the settings shine.
Grid or list, a toggle song—
LycheeState hums along.
Tiny badges, a joyful bind.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.85% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 095bb4b and d8c7734.

📒 Files selected for processing (3)
  • app/Metadata/Versions/Remote/GitCommits.php
  • app/Metadata/Versions/Remote/GitTags.php
  • tests/Unit/Metadata/GitHubVersionTest.php
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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/Metadata/Versions/Remote/GitCommits.php
  • tests/Unit/Metadata/GitHubVersionTest.php
  • app/Metadata/Versions/Remote/GitTags.php
tests/Unit/**/*.php

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

Tests in the tests/Unit directory should extend from AbstractTestCase

Files:

  • tests/Unit/Metadata/GitHubVersionTest.php
tests/**/*.php

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

No need to mock the database in tests; use the in-memory SQLite database instead

Files:

  • tests/Unit/Metadata/GitHubVersionTest.php
🧠 Learnings (2)
📓 Common learnings
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3626
File: database/migrations/2025_06_07_144157_photo_tags_to_table.php:87-105
Timestamp: 2025-08-18T10:19:04.946Z
Learning: In the Lychee photo management system, the migration `2025_06_07_144157_photo_tags_to_table.php` runs on data that only contains comma-separated tag names in tag_albums.show_tags - OR/AND expressions do not exist at this migration time, so handling them is unnecessary.
📚 Learning: 2025-12-28T18:12:55.752Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3901
File: app/Providers/AppServiceProvider.php:0-0
Timestamp: 2025-12-28T18:12:55.752Z
Learning: When using Laravel Octane's tick API, Octane::tick(...) returns an InvokeTickCallable that only has ->seconds(int) and ->immediate() methods. There is no ->every(N) method. Use the correct usage: Octane::tick('name', fn() => ...)->seconds(N) or Octane::tick('name', fn() => ..., N). Apply this guideline to PHP files across the project (not just AppServiceProvider.php).

Applied to files:

  • app/Metadata/Versions/Remote/GitCommits.php
  • tests/Unit/Metadata/GitHubVersionTest.php
  • app/Metadata/Versions/Remote/GitTags.php
🧬 Code graph analysis (3)
app/Metadata/Versions/Remote/GitCommits.php (1)
app/Metadata/Versions/Remote/AbstractGitRemote.php (1)
  • AbstractGitRemote (14-117)
tests/Unit/Metadata/GitHubVersionTest.php (5)
app/Metadata/Json/CommitsRequest.php (1)
  • CommitsRequest (14-29)
app/Metadata/Json/TagsRequest.php (1)
  • TagsRequest (14-28)
app/Metadata/Versions/GitHubVersion.php (3)
  • GitHubVersion (33-237)
  • isMasterBranch (77-80)
  • getBehindTest (93-109)
app/Metadata/Versions/Remote/GitCommits.php (1)
  • GitCommits (38-73)
app/Metadata/Versions/Remote/GitTags.php (1)
  • GitTags (31-87)
app/Metadata/Versions/Remote/GitTags.php (1)
app/Metadata/Versions/Remote/AbstractGitRemote.php (1)
  • AbstractGitRemote (14-117)
⏰ 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). (12)
  • GitHub Check: 2️⃣ PHP dist / 8.5 - mariadb
  • GitHub Check: 2️⃣ PHP dist / 8.4 - sqlite
  • GitHub Check: 2️⃣ PHP dist / 8.4 - mariadb
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Feature_v2
  • 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 - postgresql -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
🔇 Additional comments (3)
app/Metadata/Versions/Remote/GitTags.php (1)

31-31: Clarify the reason for removing the final modifier.

The final keyword was removed from the class declaration, allowing GitTags to be extended. While this doesn't introduce bugs, it changes the class's design contract and appears unrelated to the PR's album layout feature.

Modern PHP best practices recommend classes be final by default unless inheritance is explicitly needed. Please clarify:

  • Is there a new subclass of GitTags introduced elsewhere?
  • Is this needed for testing/mocking purposes?
  • Or is this preparatory work for future extensibility?

If there's no immediate need for inheritance, consider keeping the class final to preserve the original design intent.

tests/Unit/Metadata/GitHubVersionTest.php (1)

1-804: Excellent test coverage!

This test file demonstrates comprehensive unit testing best practices:

  • Properly extends AbstractTestCase as required by coding guidelines
  • Includes correct license header
  • Thorough coverage of all GitHubVersion behaviors (hydration, version checks, permissions, edge cases)
  • Appropriate use of mocks for filesystem and logging operations
  • Clear, descriptive test method names following the "testMethodNameWith[Scenario]" pattern
  • Proper cleanup in tearDown() with \Mockery::close()
  • Edge cases well-covered (unreadable files, missing Git directory, feature branches)
  • All assertions are appropriately strict (assertTrue/assertFalse for booleans, assertNull for null checks, assertEquals for strings)

The test structure follows the AAA (Arrange-Act-Assert) pattern consistently, making the tests easy to understand and maintain.

app/Metadata/Versions/Remote/GitCommits.php (1)

38-38: No issues identified. The removal of final was applied consistently to both GitCommits and GitTags classes, indicating a deliberate architectural decision. No existing subclasses in the codebase currently rely on or extend these classes. The parent class AbstractGitRemote retains final methods to protect core behavior, and both classes implement the GitRemote interface, which provides a contract for any future subclasses. This change is safe and does not compromise the existing design.


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

@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

Caution

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

⚠️ Outside diff range comments (3)
docs/specs/4-architecture/features/005-album-list-view/spec.md (2)

14-30: INCONSISTENCY: Overview contradicts Goals regarding user preference persistence.

The Overview section (line 17) states user preference is "NOT persisted to the server—it resets to the admin-configured default on page reload," but the Goals section (line 23) explicitly lists "Persist user view preference across sessions using localStorage." These are fundamentally incompatible requirements.

Per the Refined Behavior documented in Appendix (line 371), the intended behavior is no persistence (session-only, reset on reload). The Goals section should be corrected to align with this decision.

🔎 Proposed fix for Goals consistency

Remove the localStorage persistence goal from the Goals section:

## Goals
- Provide an alternative list view for albums that prioritizes information density and scannability over visual thumbnails
- Display full, untruncated album names to improve discoverability for albums with long titles
- Show album metadata (photo count, sub-album count) inline for quick scanning
-- Persist user view preference across sessions using localStorage
- Maintain existing grid view functionality with seamless toggle capability

350-481: Missing required footer: spec should end with --- (HR line) followed by _Last updated: 2026-01-04_

Per coding guidelines for docs/specs/4-architecture/features/**/*.md files, documentation should include an HR line at the bottom followed by "Last updated: [date]" for audit trail.

🔎 Proposed addition to end of spec.md

After the Appendix section, add:

 ### InitConfig Response Example
 
 ```json
 {
   "config": {
     "are_nsfw_visible": false,
     "album_layout": "grid",
     ...
   }
 }

Note: The album_layout value is the admin-configured default from the database. Users can toggle views client-side, but their preference is not sent back to the server.
+
+---
+
+Last updated: 2026-01-04

</details>

</blockquote></details>
<details>
<summary>docs/specs/4-architecture/features/005-album-list-view/tasks.md (1)</summary><blockquote>

`1-10`: **Task checklist structure is well-organized, but completion status inconsistency with spec status.**

The tasks are clearly organized by increments (I1-I18) with detailed Intent, Verification commands, and Notes sections. However, spec.md claims status "Implemented" while 5 tasks remain pending (T-005-53-56, T-005-66: component unit tests and knowledge-map documentation).

Per coding guidelines, specs should reflect current state. If tasks are genuinely incomplete, spec status should be "In Progress" or "Ready for Implementation," not "Implemented."


<details>
<summary>🔎 Recommended alignment</summary>

Choose one approach:

**Option A: Mark spec as "In Progress" (if tests are incomplete)**
```diff
# Feature 005 – Album List View Toggle

| Field | Value |
|-------|-------|
- | Status | Implemented |
+ | Status | In Progress |

Option B: Mark remaining tasks as [x] (if work is actually done)
Lines 401, 407, 413, 419, 496 - change [ ] to [x] for pending component/doc tasks if testing has been done.

Recommend Option A if unit tests are not yet written/verified.

🧹 Nitpick comments (3)
resources/js/components/gallery/albumModule/thumbs/ListBadge.vue (2)

4-5: Replace deprecated xlink:href with href.

The xlink:href attribute is deprecated in SVG2 and modern browsers. Use href directly instead.

🔎 Proposed fix
-		<svg v-if="props.icon" class="iconic inline w-4 h-4" :class="props.class">
-			<use :xlink:href="iconHref" />
+		<svg v-if="props.icon" class="iconic inline w-4 h-4" :class="props.class">
+			<use :href="iconHref" />

12-16: Consider renaming the class prop to avoid confusion.

The prop name class conflicts with the native HTML attribute and may cause confusion. Consider renaming to iconClass or svgClass for clarity.

🔎 Proposed refactor
 const props = defineProps<{
-	class: string;
+	iconClass: string;
 	icon?: string;
 	pi?: string;
 }>();

And update the template:

-		<svg v-if="props.icon" class="iconic inline w-4 h-4" :class="props.class">
+		<svg v-if="props.icon" class="iconic inline w-4 h-4" :class="props.iconClass">
resources/js/components/gallery/albumModule/AlbumThumbPanel.vue (1)

136-148: Consider performance impact of findIndex on every click.

The propagateClickedFromList and propagateMenuOpenFromList functions use findIndex to locate the album, which is O(n) and runs on every click event. For large album collections, this could cause noticeable delays.

Consider one of these approaches:

  1. Pass index directly from AlbumListItem: Modify AlbumListItem to emit the index alongside the album object, eliminating the need for findIndex.

  2. Create an index map: Build a Map<album_id, index> once when albums change:

const albumIndexMap = computed(() => {
	const map = new Map<string, number>();
	props.albums.forEach((album, idx) => {
		map.set(album.id, idx + props.idxShift);
	});
	return map;
});

const propagateClickedFromList = (e: MouseEvent, album: App.Http.Resources.Models.ThumbAlbumResource) => {
	const idx = albumIndexMap.value.get(album.id);
	if (idx !== undefined) {
		emits("clicked", idx, e);
	}
};

This reduces click handler complexity from O(n) to O(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 a346e50 and 0386ff4.

📒 Files selected for processing (18)
  • app/Enum/AlbumLayoutType.php
  • app/Http/Resources/GalleryConfigs/InitConfig.php
  • app/Http/Resources/Models/Utils/TimelineData.php
  • database/migrations/2026_01_04_000000_add_album_layout_config.php
  • docs/specs/4-architecture/features/005-album-list-view/REFINEMENTS-2026-01-04.md
  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
  • docs/specs/4-architecture/roadmap.md
  • resources/js/components/gallery/albumModule/AlbumHero.vue
  • resources/js/components/gallery/albumModule/AlbumListItem.vue
  • resources/js/components/gallery/albumModule/AlbumListView.vue
  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
  • resources/js/components/gallery/albumModule/thumbs/ListBadge.vue
  • resources/js/components/headers/AlbumsHeader.vue
  • resources/js/lychee.d.ts
  • resources/js/stores/LycheeState.ts
🧰 Additional context used
📓 Path-based instructions (9)
**/*.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/headers/AlbumsHeader.vue
  • resources/js/components/gallery/albumModule/AlbumHero.vue
  • resources/js/components/gallery/albumModule/thumbs/ListBadge.vue
  • resources/js/components/gallery/albumModule/AlbumListItem.vue
  • resources/js/components/gallery/albumModule/AlbumListView.vue
  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
**/*.{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/components/headers/AlbumsHeader.vue
  • resources/js/stores/LycheeState.ts
  • resources/js/components/gallery/albumModule/AlbumHero.vue
  • resources/js/components/gallery/albumModule/thumbs/ListBadge.vue
  • resources/js/components/gallery/albumModule/AlbumListItem.vue
  • resources/js/components/gallery/albumModule/AlbumListView.vue
  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
  • resources/js/lychee.d.ts
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.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/components/headers/AlbumsHeader.vue
  • resources/js/stores/LycheeState.ts
  • resources/js/components/gallery/albumModule/AlbumHero.vue
  • resources/js/components/gallery/albumModule/thumbs/ListBadge.vue
  • resources/js/components/gallery/albumModule/AlbumListItem.vue
  • resources/js/components/gallery/albumModule/AlbumListView.vue
  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
  • resources/js/lychee.d.ts
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
**/*.md

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

**/*.md: Use Markdown format for documentation
At the bottom of documentation files, add an hr line followed by "Last updated: [date of the update]"

Files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/REFINEMENTS-2026-01-04.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/roadmap.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
docs/specs/4-architecture/features/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/specs/4-architecture/features/**/*.md: Author new specifications, feature plans, and task checklists using docs/specs/templates/feature-spec-template.md, docs/specs/templates/feature-plan-template.md, and docs/specs/templates/feature-tasks-template.md to keep structure, metadata, and verification notes uniform across features.
For any new UI feature or modification, include an ASCII mock-up in the specification (see docs/specs/4-architecture/spec-guidelines/ui-ascii-mockups.md).
When revising a specification, only document fallback or compatibility behaviour if the user explicitly asked for it; if instructions are unclear, pause and request confirmation instead of assuming a fallback.
For every task, refresh the relevant feature plan and note open questions; only move forward once the plan reflects the desired change. Update specs before code.
Update feature specs, feature plans, and tasks documents as progress is made and sync context to disk.
Capture prompt summaries, command sequences, and rationale in the active feature plan or an appendix referenced from it so downstream reviewers know how the change was produced (intent logging).
Track upcoming additions for contract tests, mutation analysis, and security/red-team prompt suites in the plans until automated jobs exist (quality gates).
Publish prompt and tool usage notes alongside the feature plan update so future agents understand how the iteration unfolded.

Files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/REFINEMENTS-2026-01-04.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
docs/specs/4-architecture/features/**/{spec,plan,tasks}.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/specs/4-architecture/features/**/{spec,plan,tasks}.md: Start every feature by updating or creating its specification at docs/specs/4-architecture/features/-/spec.md, followed by plan and tasks documents after clarifications are resolved.
Generate or refresh the feature plan only after the specification is current and high-/medium-impact clarifications are resolved and recorded in the spec (plus ADRs where required).

Files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
**/*.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/Resources/GalleryConfigs/InitConfig.php
  • database/migrations/2026_01_04_000000_add_album_layout_config.php
  • app/Enum/AlbumLayoutType.php
  • app/Http/Resources/Models/Utils/TimelineData.php
docs/specs/4-architecture/roadmap.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/specs/4-architecture/roadmap.md: Update the roadmap regularly to reflect feature status and progress as work is made.
Keep high-level plans in docs/specs/4-architecture/roadmap.md, store each feature's spec/plan/tasks inside docs/specs/4-architecture/features/-/, and remove plans once work is complete.

Files:

  • docs/specs/4-architecture/roadmap.md
docs/specs/4-architecture/features/**/tasks.md

📄 CodeRabbit inference engine (AGENTS.md)

docs/specs/4-architecture/features/**/tasks.md: Maintain a per-feature tasks checklist that mirrors the plan, orders tests before code, and keeps planned increments ≤90 minutes by preferring finer-grained entries and documenting sub-steps when something nears the limit.
Mark each task [x] in the feature's tasks.md as soon as it passes verification. Do not batch task completions—update the checklist after every individual task so progress is always visible.
Before committing, confirm every completed task in tasks.md is marked [x] and the roadmap status reflects current progress (validate task checklist).

Files:

  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
🧠 Learnings (34)
📚 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 docs/specs/4-architecture/features/**/*.md : Capture prompt summaries, command sequences, and rationale in the active feature plan or an appendix referenced from it so downstream reviewers know how the change was produced (intent logging).

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/REFINEMENTS-2026-01-04.md
📚 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 docs/specs/4-architecture/features/**/*.md : Track upcoming additions for contract tests, mutation analysis, and security/red-team prompt suites in the plans until automated jobs exist (quality gates).

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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 docs/specs/4-architecture/features/**/*.md : For every task, refresh the relevant feature plan and note open questions; only move forward once the plan reflects the desired change. Update specs before code.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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 docs/specs/4-architecture/features/**/{spec,plan,tasks}.md : Generate or refresh the feature plan only after the specification is current and high-/medium-impact clarifications are resolved and recorded in the spec (plus ADRs where required).

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/REFINEMENTS-2026-01-04.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
📚 Learning: 2025-08-16T10:57:51.480Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3504
File: resources/js/views/gallery-panels/Albums.vue:11-13
Timestamp: 2025-08-16T10:57:51.480Z
Learning: In resources/js/views/gallery-panels/Albums.vue, the SelectDrag component is intentionally configured with :with-scroll="false" even though the #galleryView container has overflow-y-auto. This is working as intended according to the maintainer, who suggested that overflow-y-auto might be removed instead.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • resources/js/components/gallery/albumModule/AlbumHero.vue
  • docs/specs/4-architecture/features/005-album-list-view/REFINEMENTS-2026-01-04.md
  • resources/js/components/gallery/albumModule/AlbumListView.vue
  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
📚 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 docs/specs/4-architecture/features/**/tasks.md : Before committing, confirm every completed task in tasks.md is marked [x] and the roadmap status reflects current progress (validate task checklist).

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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 docs/specs/4-architecture/features/**/tasks.md : Maintain a per-feature tasks checklist that mirrors the plan, orders tests before code, and keeps planned increments ≤90 minutes by preferring finer-grained entries and documenting sub-steps when something nears the limit.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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 docs/specs/4-architecture/features/**/tasks.md : Mark each task [x] in the feature's tasks.md as soon as it passes verification. Do not batch task completions—update the checklist after every individual task so progress is always visible.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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 docs/specs/4-architecture/open-questions.md : Update or close entries in docs/specs/4-architecture/open-questions.md after completing work.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
  • docs/specs/4-architecture/features/005-album-list-view/spec.md
📚 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 docs/specs/5-operations/analysis-gate-checklist.md : Run the analysis gate in docs/specs/5-operations/analysis-gate-checklist.md once spec, plan, and tasks agree; address findings before implementation.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
📚 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: Before hand-off, review your own changes, rerun checks, and ensure documentation/test coverage matches the behaviour (RCI self-review).

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/plan.md
📚 Learning: 2025-08-22T18:56:08.725Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3642
File: resources/js/components/gallery/albumModule/AlbumHero.vue:173-183
Timestamp: 2025-08-22T18:56:08.725Z
Learning: In the needSizeVariantsWatermark function in resources/js/components/gallery/albumModule/AlbumHero.vue, the original variant is intentionally excluded from the watermark check. This is a deliberate design decision to not consider original files when determining if the watermark button should be shown.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
📚 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:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
📚 Learning: 2025-12-28T18:12:55.752Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3901
File: app/Providers/AppServiceProvider.php:0-0
Timestamp: 2025-12-28T18:12:55.752Z
Learning: When using Laravel Octane's tick API, Octane::tick(...) returns an InvokeTickCallable that only has ->seconds(int) and ->immediate() methods. There is no ->every(N) method. Use the correct usage: Octane::tick('name', fn() => ...)->seconds(N) or Octane::tick('name', fn() => ..., N). Apply this guideline to PHP files across the project (not just AppServiceProvider.php).

Applied to files:

  • app/Http/Resources/GalleryConfigs/InitConfig.php
  • database/migrations/2026_01_04_000000_add_album_layout_config.php
  • app/Enum/AlbumLayoutType.php
  • app/Http/Resources/Models/Utils/TimelineData.php
📚 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 docs/specs/5-decisions/**/*.md : Before planning or implementation, skim ADRs under docs/specs/5-decisions whose related-features/specs entries reference the active feature ID so high-impact clarifications and architectural decisions are treated as required context.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/REFINEMENTS-2026-01-04.md
📚 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 docs/specs/4-architecture/roadmap.md : Update the roadmap regularly to reflect feature status and progress as work is made.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/roadmap.md
📚 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 docs/specs/4-architecture/roadmap.md : Keep high-level plans in docs/specs/4-architecture/roadmap.md, store each feature's spec/plan/tasks inside docs/specs/4-architecture/features/<NNN>-<feature-name>/, and remove plans once work is complete.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/spec.md
  • docs/specs/4-architecture/roadmap.md
📚 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 docs/specs/4-architecture/features/**/{spec,plan,tasks}.md : Start every feature by updating or creating its specification at docs/specs/4-architecture/features/<NNN>-<feature-name>/spec.md, followed by plan and tasks documents after clarifications are resolved.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/spec.md
📚 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 docs/specs/4-architecture/features/**/*.md : Update feature specs, feature plans, and tasks documents as progress is made and sync context to disk.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/spec.md
📚 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 docs/specs/4-architecture/open-questions.md : Capture every high-impact clarification question and each medium-impact uncertainty per feature in docs/specs/4-architecture/open-questions.md and, once resolved, record the outcome directly in the spec (requirements, NFR, behaviour/UI, telemetry/policy sections).

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/spec.md
📚 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 docs/specs/4-architecture/open-questions.md : Log high- and medium-impact open questions in docs/specs/4-architecture/open-questions.md and remove each row as soon as it is resolved, ensuring the answer is captured first in the governing spec's normative sections.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/spec.md
📚 Learning: 2025-08-16T10:55:08.753Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3504
File: resources/js/components/gallery/albumModule/thumbs/AlbumThumbImage.vue:41-42
Timestamp: 2025-08-16T10:55:08.753Z
Learning: In AlbumThumbImage.vue, the isSelectable prop is intentionally optional without a default value. When undefined, the template condition `isDragging && !isSelectable ? '' : props.class` will strip props.class during dragging by design. Components should explicitly pass isSelectable={true} if they want to preserve styling during drag operations.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumListItem.vue
  • resources/js/components/gallery/albumModule/AlbumListView.vue
  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
📚 Learning: 2025-08-18T10:19:04.946Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3626
File: database/migrations/2025_06_07_144157_photo_tags_to_table.php:87-105
Timestamp: 2025-08-18T10:19:04.946Z
Learning: In the Lychee photo management system, the migration `2025_06_07_144157_photo_tags_to_table.php` runs on data that only contains comma-separated tag names in tag_albums.show_tags - OR/AND expressions do not exist at this migration time, so handling them is unnecessary.

Applied to files:

  • docs/specs/4-architecture/roadmap.md
  • database/migrations/2026_01_04_000000_add_album_layout_config.php
📚 Learning: 2025-08-16T14:00:53.808Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3504
File: resources/js/composables/selections/selections.ts:145-147
Timestamp: 2025-08-16T14:00:53.808Z
Learning: In the Lychee codebase, the maintainer ildyria has indicated that bounds checking for array access in selectables.albums.value[idx] within the albumClick function in resources/js/composables/selections/selections.ts is not necessary, suggesting there are adequate safeguards elsewhere in the code or the access pattern is guaranteed to be safe.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumListView.vue
  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
📚 Learning: 2025-09-22T12:35:38.842Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3706
File: tests/Unit/Http/Controllers/ImportFromServerControllerTest.php:59-66
Timestamp: 2025-09-22T12:35:38.842Z
Learning: In the Lychee codebase, the Configs class extends Laravel's Model, making config values database-backed. Tests using the DatabaseTransactions trait automatically have config changes rolled back without requiring manual restoration in tearDown() methods.

Applied to files:

  • database/migrations/2026_01_04_000000_add_album_layout_config.php
📚 Learning: 2025-08-16T10:56:04.248Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3504
File: resources/js/composables/album/dragAndSelect.ts:68-74
Timestamp: 2025-08-16T10:56:04.248Z
Learning: In the Lychee drag-and-select implementation (resources/js/composables/album/dragAndSelect.ts), the X offset handling is intentionally not implemented as it's not needed for the functionality. The current coordinate system mixing pageY with viewport-based rects has been tested and works as expected.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
📚 Learning: 2025-11-30T17:19:00.773Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3837
File: resources/js/composables/checkout/useStepTwo.ts:8-16
Timestamp: 2025-11-30T17:19:00.773Z
Learning: In the Lychee project's checkout composables (resources/js/composables/checkout/), module-level refs that cause state sharing across component instances are intentional architectural choices, not issues to flag.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumThumbPanel.vue
📚 Learning: 2025-09-28T08:46:37.299Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3721
File: resources/js/stores/UserState.ts:7-11
Timestamp: 2025-09-28T08:46:37.299Z
Learning: In Lychee codebase, the type `App.Enum.OauthProvidersType` is properly defined within the `App.Enum` namespace in `resources/js/lychee.d.ts` file. References to `App.Enum.OauthProvidersType` in TypeScript files are valid and resolve correctly.

Applied to files:

  • resources/js/lychee.d.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 **/*.{vue,ts,js,css} : For frontend changes, run npm run format to apply frontend code formatting with Prettier before committing.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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:

  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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 Vue3/TypeScript frontend code, follow coding conventions defined in docs/specs/3-reference/coding-conventions.md for style, naming, and testing practices.

Applied to files:

  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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:

  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 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:

  • docs/specs/4-architecture/features/005-album-list-view/tasks.md
📚 Learning: 2025-09-28T08:27:38.332Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3721
File: resources/js/composables/album/photoActions.ts:39-43
Timestamp: 2025-09-28T08:27:38.332Z
Learning: The user ildyria (repository maintainer) prefers to skip error handling for the rotate photo functions (rotatePhotoCW and rotatePhotoCCW) in resources/js/composables/album/photoActions.ts.

Applied to files:

  • resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue
🧬 Code graph analysis (1)
app/Http/Resources/GalleryConfigs/InitConfig.php (1)
resources/js/lychee.d.ts (1)
  • AlbumLayoutType (18-18)
🪛 LanguageTool
docs/specs/4-architecture/features/005-album-list-view/plan.md

[grammar] ~725-~725: Ensure spelling is correct
Context: ...st view 5. Verify list view rendering < 300ms (NFR-005-02) 6. If performance issues: ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~735-~735: Ensure spelling is correct
Context: ...** List view rendering completes within 300ms for 100 albums Implements: NFR-005...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

docs/specs/4-architecture/features/005-album-list-view/tasks.md

[grammar] ~480-~480: Ensure spelling is correct
Context: ...lbums, measure rendering time, verify < 300ms for list view. _Verification commands...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[uncategorized] ~531-~531: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...p to date - Ensure PHP and Composer are up to date - Run npm install and `composer insta...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

⏰ 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️⃣ Dockerfile Lint
  • GitHub Check: 2️⃣ PHP dist / 8.5 - postgresql
  • GitHub Check: 2️⃣ PHP dist / 8.5 - sqlite
  • GitHub Check: 2️⃣ PHP dist / 8.4 - sqlite
  • GitHub Check: 2️⃣ PHP dist / 8.5 - mariadb
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Precomputing
  • 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 -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
🔇 Additional comments (30)
app/Enum/AlbumLayoutType.php (1)

1-20: LGTM! Clean enum implementation.

The enum follows all PHP coding guidelines with proper license header, namespace declaration, and PHPDoc. The string-backed enum with LIST and GRID cases provides type-safe layout configuration that integrates well with the frontend state management.

app/Http/Resources/Models/Utils/TimelineData.php (1)

103-103: Good defensive coding practice.

Adding trim() ensures that album titles with leading or trailing whitespace can still be parsed correctly by the regex pattern. Since the pattern uses the ^ anchor, leading whitespace would otherwise prevent matching.

resources/js/stores/LycheeState.ts (1)

45-45: LGTM! Proper state management.

The album_view_mode property is correctly typed as App.Enum.AlbumLayoutType, initialized with a sensible default ("grid"), and properly populated from the backend album_layout configuration during the load flow. This follows the established pattern for other state properties.

Also applies to: 169-169

docs/specs/4-architecture/roadmap.md (1)

16-16: LGTM! Roadmap properly updated.

Feature 005 (Album List View Toggle) has been correctly moved to the Completed Features table with descriptive notes and the timestamp updated to reflect the current date. This follows the guidelines for maintaining the roadmap.

Also applies to: 82-82

resources/js/components/headers/AlbumsHeader.vue (1)

191-197: LGTM! Clean toggle implementation.

The view-switching functions follow Vue3 conventions (using function functionName() {} syntax) and the menu items are properly structured with conditional display logic. The mutually exclusive toggle behavior (showing grid icon when in list mode, and vice versa) provides good UX.

Also applies to: 268-281

resources/js/lychee.d.ts (2)

18-18: LGTM! Type definition is clean and consistent.

The AlbumLayoutType enum follows the established pattern for TypeScript enum declarations in this namespace and correctly matches the backend enum values.


381-381: LGTM! InitConfig property addition follows the established pattern.

The album_layout property is correctly typed and positioned appropriately within the InitConfig interface structure.

app/Http/Resources/GalleryConfigs/InitConfig.php (3)

13-13: LGTM! Import follows established patterns.

The import for AlbumLayoutType is correctly placed alphabetically among the other enum imports.


64-65: LGTM! Property declaration is well-documented and properly typed.

The comment and property declaration follow the same style and structure as other configuration properties in this class.


159-159: LGTM! Initialization follows the established enum config pattern.

The initialization using getValueAsEnum() is consistent with other enum configurations in the constructor (lines 137, 142, 151-155, etc.).

resources/js/components/gallery/albumModule/thumbs/AlbumThumb.vue (2)

20-32: LGTM! RTL drag workaround is well-documented.

The conditional rendering of decorative thumb images during drag operations is a reasonable workaround for RTL mode issues. The comment clearly explains the intent, and the main (third) thumb image remains visible to preserve the visual structure.

The added top-0 left-0 positioning classes ensure consistent alignment across all thumb layers.


34-34: LGTM! Positioning alignment is consistent.

The top-0 left-0 classes align this thumb image with the positioning of the other layers for visual consistency.

resources/js/components/gallery/albumModule/AlbumHero.vue (2)

161-161: LGTM! PrimeVue Button import follows project guidelines.

The import is correctly placed and aligns with the project's requirement to use PrimeVue for UI components.


181-183: LGTM! Toggle function is straightforward and follows Vue3 guidelines.

The function uses the proper function declaration syntax (not arrow function) and directly updates the Lychee store state. The implementation is clean and appropriate for this use case.

database/migrations/2026_01_04_000000_add_album_layout_config.php (1)

1-35: LGTM! Migration follows all guidelines and integrates cleanly.

The migration structure correctly extends BaseConfigMigration and follows the established pattern for config migrations in the codebase. Key observations:

  • License header is properly formatted with correct copyright years
  • Config structure includes all required fields with appropriate values
  • Type range grid|list matches the backend AlbumLayoutType enum and frontend TypeScript definitions
  • Default value grid aligns with expected behavior
  • The details field helpfully explains that user preference doesn't persist across reloads, which is important UX information
  • Order value (50) places this config appropriately within the Gallery category
resources/js/components/gallery/albumModule/AlbumListView.vue (1)

1-32: LGTM!

The component correctly renders album list items with NSFW filtering and proper event forwarding. The structure follows Vue 3 composition API best practices.

resources/js/components/gallery/albumModule/AlbumListItem.vue (1)

67-68: Verify the password lock badge color logic.

The current logic shows:

  • Orange lock when password required AND no thumb (Line 67)
  • Red lock when password required AND thumb exists (Line 68)

This seems counterintuitive: showing red (danger) when unlocked and orange (warning) when locked. Typically, locked content is more restrictive (red) and unlocked is safer (green/orange). Please verify this is the intended design.

If the intent is to show that unlocked password-protected content is "exposed" (hence red/danger), consider adding a comment explaining this logic for future maintainers.

resources/js/components/gallery/albumModule/AlbumThumbPanel.vue (1)

163-165: Verify the specific padding logic for list view.

The paddingTopClass applies pt-4 only when isAlone && album_view_mode === "list". This is very specific—please confirm this is the intended behavior and not a case that should also apply to grid view when alone.

If this is intentional, consider adding a comment explaining why list view needs top padding when alone but grid view doesn't.

docs/specs/4-architecture/features/005-album-list-view/plan.md (5)

1-10: Plan document structure is comprehensive and well-formatted.

The metadata, vision statement, and scope alignment are clearly articulated. Footer format (HR + last updated) complies with coding guidelines. Overall document meets plan template expectations.


137-288: Increments I1-I5 are well-structured with clear preconditions and actionable steps.

Backend and initial frontend components (config migration, InitConfig, LycheeState, AlbumListItem, AlbumListView) have explicit code references and verification commands. Each step is granular and testable.


715-738: Performance testing increments include realistic measurements and memory profiling.

The NFR-005-02 requirement (300ms rendering for 100 albums) is properly translated into actionable measurement steps. Reference to IMPLEMENTATION-SNIPPETS.md for code is clear.


796-817: Analysis gate was executed and findings are documented with architectural decisions captured.

The checklist confirms pattern alignment with existing codebase (BaseConfigMigration, InitConfig, LycheeState). Findings section documents simplified architecture choices (no localStorage, no new API endpoints).


818-871: Exit criteria are comprehensive and checkboxes reflect pre-implementation state.

All major categories (backend, frontend, manual testing, quality gates, documentation) are covered. Follow-ups and known limitations are appropriately deferred and documented.

docs/specs/4-architecture/features/005-album-list-view/spec.md (4)

34-53: Functional and Non-Functional requirements are comprehensive and well-sourced.

All major capabilities (list view, toggle, backend config, selection, drag-select, zero-count hiding, responsiveness) are covered. NFR requirements address performance (300ms for 100 albums), accessibility, and code quality standards.


57-197: ASCII mockups effectively demonstrate grid vs list layouts, RTL mode, and responsive mobile design.

Each mockup includes a legend explaining thumbnail sizes, icon usage, count visibility rules, and alignment direction. The mockups provide clear visual reference for implementation without requiring screenshots.


199-237: Scenario matrix and test strategy are comprehensive and well-layered.

20 scenarios cover toggle behavior, admin defaults, count hiding, responsiveness, RTL, selection, and edge cases. Test strategy includes core/REST/UI tests with fixture data defined. All scenarios are traceable to functional requirements.


239-481: Interface catalogue and appendix provide excellent implementation guidance and decision rationale.

The contract catalogue confirms no new API endpoints are needed (uses existing InitConfig). Appendix documents resolved open questions (Q-005-01, Q-005-02, Q-005-03) with implementation notes covering backend, components, state management, styling, accessibility, and data flow. Refinements section captures iterative clarifications.

docs/specs/4-architecture/features/005-album-list-view/tasks.md (3)

13-70: Task definitions are granular and include specific verification commands and code references.

Each task (T-005-01 through T-005-70) follows a consistent structure: Intent, Verification commands, and Notes. Code references point to IMPLEMENTATION-SNIPPETS.md (assumed to be available). Verification commands are actionable (e.g., php artisan migrate, npm run check).


401-523: Pending tasks (T-005-53-56, T-005-66) are test and documentation work, not implementation.

The fixture creation (T-005-53), component unit tests (T-005-54-56), and knowledge-map update (T-005-66) are marked as pending. However, spec.md claims status "Implemented." This is a critical inconsistency.

Per coding guidelines, tests should be staged and marked [x] as soon as they pass verification. The pending status suggests either:

  1. These tests were deferred and need to be completed before PR merge, OR
  2. These tests were completed but status was not updated in tasks.md

Recommend clarifying: update spec status to "In Progress" OR mark test tasks [x] with verification notes.


527-571: Notes/TODOs section is practical and footer is properly formatted.

Environment setup, testing strategy, deferred items, common commands, architecture patterns, and potential blockers are all documented. Footer correctly includes HR line and last updated date, complying with coding guidelines.

Copy link

@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

🧹 Nitpick comments (1)
resources/js/stores/CatalogState.ts (1)

28-28: LGTM! Guard clause correctly prevents catalog fetch for short album IDs.

The new length check safely filters out invalid or incomplete album IDs. The short-circuit evaluation ensures .length is never accessed when albumId is undefined.

💡 Optional: Extract magic number to a named constant

For improved maintainability, consider extracting the magic number 24 to a named constant:

+const MIN_ALBUM_ID_LENGTH = 24;
+
 export const useCatalogStore = defineStore("catalog-store", {
   // ...
   actions: {
     load(): Promise<void> {
       // ...
-      if (this.albumId === ALL || this.albumId === undefined || this.albumId.length < 24) {
+      if (this.albumId === ALL || this.albumId === undefined || this.albumId.length < MIN_ALBUM_ID_LENGTH) {
         return Promise.resolve();
       }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0386ff4 and 7c7dfb0.

📒 Files selected for processing (2)
  • resources/js/components/gallery/albumModule/AlbumHero.vue
  • resources/js/stores/CatalogState.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • resources/js/components/gallery/albumModule/AlbumHero.vue
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{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/stores/CatalogState.ts
**/*.{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/stores/CatalogState.ts
🧠 Learnings (1)
📚 Learning: 2025-09-28T12:43:29.852Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3721
File: resources/js/views/gallery-panels/Album.vue:200-204
Timestamp: 2025-09-28T12:43:29.852Z
Learning: The photoStore.load() method in resources/js/stores/PhotoState.ts already handles undefined photoId cases internally with a short circuit exit, so conditional checks before calling photoStore.load() are unnecessary.

Applied to files:

  • resources/js/stores/CatalogState.ts
🧬 Code graph analysis (1)
resources/js/stores/CatalogState.ts (1)
resources/js/config/constants.ts (1)
  • ALL (2-2)
⏰ 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: 2️⃣ PHP dist / 8.4 - postgresql
  • GitHub Check: 2️⃣ PHP dist / 8.4 - sqlite
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.4 - mariadb -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.4 - postgresql -- Install

Copy link

@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 7c7dfb0 and 095bb4b.

📒 Files selected for processing (1)
  • resources/js/components/gallery/albumModule/AlbumHero.vue
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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/gallery/albumModule/AlbumHero.vue
**/*.{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/components/gallery/albumModule/AlbumHero.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/components/gallery/albumModule/AlbumHero.vue
🧠 Learnings (6)
📚 Learning: 2025-08-16T10:57:51.480Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3504
File: resources/js/views/gallery-panels/Albums.vue:11-13
Timestamp: 2025-08-16T10:57:51.480Z
Learning: In resources/js/views/gallery-panels/Albums.vue, the SelectDrag component is intentionally configured with :with-scroll="false" even though the #galleryView container has overflow-y-auto. This is working as intended according to the maintainer, who suggested that overflow-y-auto might be removed instead.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
📚 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:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
📚 Learning: 2025-08-20T20:35:04.474Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3637
File: lang/nl/renamer.php:10-94
Timestamp: 2025-08-20T20:35:04.474Z
Learning: In Lychee, translation files are initially created with English strings as placeholders, and actual translations are handled through Weblate (a web-based translation management system). This means finding English text in non-English locale files (like lang/nl/, lang/de/, etc.) is expected and part of their translation workflow, not an issue to flag.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
📚 Learning: 2025-08-27T08:48:45.672Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3654
File: lang/es/gallery.php:210-210
Timestamp: 2025-08-27T08:48:45.672Z
Learning: The project maintainer ildyria has indicated that language localization consistency is not a priority ("Lang = don't care"), meaning English text in non-English language files is acceptable and should not be flagged as an issue.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
📚 Learning: 2025-08-27T08:48:32.956Z
Learnt from: ildyria
Repo: LycheeOrg/Lychee PR: 3654
File: lang/pl/gallery.php:210-210
Timestamp: 2025-08-27T08:48:32.956Z
Learning: The user ildyria does not prioritize strict localization consistency for new menu items in language files, as indicated by their "Lang = don't care" response when suggested to translate 'Import from Server' to Polish in lang/pl/gallery.php.

Applied to files:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
📚 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:

  • resources/js/components/gallery/albumModule/AlbumHero.vue
⏰ 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.5 - mariadb
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Feature_v2
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Unit
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- ImageProcessing
  • 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 - postgresql -- ImageProcessing
  • GitHub Check: 1️⃣ PHP tests / 8.5 - postgresql -- Precomputing
  • GitHub Check: 1️⃣ PHP tests / 8.4 - mariadb -- Install
  • GitHub Check: 1️⃣ PHP tests / 8.5 - sqlite -- Webshop
  • GitHub Check: 1️⃣ PHP tests / 8.5 - mariadb -- Feature_v2
🔇 Additional comments (2)
resources/js/components/gallery/albumModule/AlbumHero.vue (2)

152-152: LGTM!

The Button import follows the established PrimeVue import pattern and aligns with the coding guidelines.


172-174: LGTM!

The function correctly:

  • Uses TypeScript union types for type safety
  • Follows the coding guideline to use function declaration syntax instead of arrow functions
  • Updates the Pinia store property directly, which will trigger Vue's reactivity system

@codecov
Copy link

codecov bot commented Jan 4, 2026

Codecov Report

❌ Patch coverage is 50.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 90.11%. Comparing base (1b64eb9) to head (d8c7734).
⚠️ Report is 2 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.

@ildyria ildyria merged commit af8359a into master Jan 4, 2026
42 checks passed
@ildyria ildyria deleted the album-line-view branch January 4, 2026 16:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants