Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
7c6d29e
docs(spec): feature 104 Flisk option, specification for review
odykyi Nov 1, 2026
24c5be1
docs(spec): feature 104, bind paths, .env step and pinned versions fr…
odykyi Nov 1, 2026
39cf640
docs(spec): feature 104, CI drift check against docker-compose.yaml
odykyi Nov 1, 2026
36e6578
docs(spec): feature 104, requirements for flisk up found on a real run
odykyi Nov 1, 2026
009aa33
docs(spec): feature 104, re-check of the flisk up requirements on Fli…
odykyi Nov 1, 2026
73db3e0
docs(spec): feature 104, FR-104-07 is fixed in Flisk 1.4.30
odykyi Nov 1, 2026
ba13e88
Merge remote-tracking branch 'up/master' into spec/104-flisk-option
odykyi Nov 1, 2026
70c8021
docs(spec): feature 104, require Flisk 1.4.30 for flisk up without wo…
odykyi Nov 1, 2026
275cfd5
docs(spec): feature 104, Python health check for facial recognition a…
odykyi Nov 1, 2026
b8fea1b
docs(spec): feature 104, checked on Flisk 1.4.31
odykyi Nov 2, 2026
5fe6de0
docs(spec): feature 104, task for FR-104-10 and Flisk 1.4.31 in T-104…
odykyi Nov 2, 2026
413cdd2
Revert .gitignore and README.md edits that slipped into the previous …
odykyi Nov 2, 2026
dbaae34
docs(spec): feature 104, review: restart parity, pinned importer, --w…
odykyi Nov 2, 2026
8dec603
docs(spec): feature 104, review: network parity, FR-104-09 scope, rep…
odykyi Nov 2, 2026
28025d4
docs(spec): feature 104, review: compare top-level volume names, dete…
odykyi Nov 2, 2026
c183a60
docs(spec): feature 104, add flisk-export compose --check as the firs…
odykyi Nov 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Open Questions – Feature 104

Open questions for [Feature 104](spec.md). Log every high- and medium-impact question here (table row + Question Details entry) before asking the user; see [open-questions-format.md](../../spec-guidelines/open-questions-format.md). Once answered, fold the outcome into [spec.md](spec.md) (and an ADR when architecturally significant), then mark the entry resolved.

## Active Questions

| Question ID | Feature | Priority | Summary | Status | Opened | Updated |
|-------------|---------|----------|---------|--------|--------|---------|
| Q-104-01 | 104 | High | Does the project want an optional Flisk start path at all? | Open | 2026-11-01 | 2026-11-01 |
| Q-104-02 | 104 | Medium | Where should the generated Compose file live? | Open | 2026-11-01 | 2026-11-01 |

## Question Details

### Q-104-01 – Optional Flisk start path
- **Option A (recommended):** Accept it as an option; `docker-compose.yaml` stays the documented main path (as biolend83/tubehaus did in #40). Pros: no change for existing users; Flisk users get `flisk up`. Cons: two descriptions of one stack, kept in step by CI.
- **Option B:** Keep it outside the repository (a gist or the Flisk docs). Pros: nothing to maintain here. Cons: drifts silently.
- **Option C:** Decline.

### Q-104-02 – Location of the generated Compose file
- **Option A (recommended):** `.autogenerated/docker-compose.yml`, committed, with a `.gitignore` exception. Pros: clearly generated. Cons: needs `--env-file .env` when run from the root.
- **Option B:** Do not commit it; generate on demand. Pros: one less file. Cons: no plain-Compose path without Flisk.
54 changes: 54 additions & 0 deletions docs/specs/4-architecture/features/104-flisk-option/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Feature Plan 104 – Flisk Option

_Linked specification:_ [spec.md](spec.md)
_Status:_ Draft
_Last updated:_ 2026-11-01

> Guardrail: Keep this plan traceable back to the governing spec. Reference FR/NFR/Scenario IDs from `spec.md` where relevant, log any new high- or medium-impact questions in the feature's [open-questions.md](open-questions.md), and assume clarifications are resolved only when the spec’s normative sections (requirements/NFR/behaviour/telemetry) and, where applicable, ADRs under `docs/specs/6-decisions/` have been updated.

## Vision & Success Criteria
Users who already use Flisk can start Lychee with `flisk up lychee`, and anyone can run the generated Compose file, with the same data as a `docker-compose.yaml` install. Success: S-104-01 … 05 pass.

## Scope Alignment
- **In scope:** FX-104-01 … 03, `docs/FLISK.md`, one README line, one `.gitignore` exception, one CI workflow.
- **Out of scope:** N-104-01 … 03.

## Dependencies & Interfaces
Flisk CLI 1.4.27 or later, flisk-import 0.15.0, @flisk-sh/flisk-export 0.8.0 (see the spec's *Pinned versions*).

## Assumptions & Risks
- **Assumptions:** maintainers accept an optional second start path (Q-104-01).
- **Risks / Mitigations:** drift between `docker-compose.yaml` and `service.json` → CI check (FR-104-04) and `flisk import .` to re-read the Compose file.

## Implementation Drift Gate
Re-run the per-service `docker compose config --no-interpolate` comparison and S-104-03 after implementation; record results in the PR.

## Increment Map
1. **I1 – Service files and generated Compose**
- _Steps:_ `FLISK_IMPORT_PACKAGE=flisk-import@0.15.0 flisk import . --yes`; `npx @flisk-sh/flisk-export@0.8.0 compose . --force`; `.gitignore` exception.
- _Commands:_ `flisk config verify`; `cp .env.example .env`; `docker compose --env-file .env -f .autogenerated/docker-compose.yml config` (bind sources must resolve to `<repo>/lychee/*`).
- _Exit:_ FR-104-01 … 03 met; comparison shows only documented differences.
2. **I2 – Docs and CI**
- _Steps:_ `docs/FLISK.md`, README line, `.github/workflows/flisk.yml`.
- _Exit:_ FR-104-04/05; S-104-04 fails as expected on a tampered file.
3. **I3 – Evidence**
- _Steps:_ S-104-01 … 05 on a fresh machine; screenshots and logs in the PR.

## Scenario Tracking

| Scenario ID | Increment / Task reference | Notes |
|-------------|---------------------------|-------|
| S-104-01 | I3 / T-104-05 | `flisk up lychee` |
| S-104-02 | I1 / T-104-02 | verified on scratch machine |
| S-104-03 | I1 / T-104-02 | verified on scratch machine |
| S-104-04 | I2 / T-104-04 | CI |
| S-104-05 | I3 / T-104-05 | profiles |

## Analysis Gate
Pending maintainer review of this specification PR.

## Exit Criteria
- All S-104 scenarios recorded; no existing file changed beyond NFR-104-01.

## Follow-ups / Backlog
- Optional: `docker-compose.minimal.yaml` as a second Flisk stack, if wanted.
82 changes: 82 additions & 0 deletions docs/specs/4-architecture/features/104-flisk-option/spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Feature 104 – Flisk Option

| Field | Value |
|-------|-------|
| Status | Draft |
| Last updated | 2026-11-01 |
| Owners | odykyi |
| Linked plan | [plan.md](plan.md) |
| Linked tasks | [tasks.md](tasks.md) |
| Roadmap entry | #104 |

> Guardrail: This specification is the single normative source of truth for the feature. Track high- and medium-impact questions in the feature's [open-questions.md](open-questions.md), encode resolved answers directly in the Requirements/NFR/Behaviour/UI/Telemetry sections below (no per-feature `## Clarifications` sections), and use ADRs under `docs/specs/6-decisions/` for architecturally significant clarifications (referencing their IDs from the relevant spec sections).

## Overview
Self-hosters start Lychee with `docker-compose.yaml`. This feature adds an **optional** second way to start the same stack with [Flisk](https://flisk.sh), a local dev/self-host launcher: one `service.json` per Compose service under `services/lychee/`, plus a Compose file generated from them in `.autogenerated/docker-compose.yml`. No PHP, frontend, API, artisan or image change; `docker-compose.yaml` stays the documented main path and is not edited. Disclosure: the author works on Flisk.

## Goals
- G-104-01: `flisk up lychee` starts the same services as `docker compose -f docker-compose.yaml up` (lychee_api, lychee_worker, lychee_db, lychee_facial_recognition; phpmyadmin, nsfw and geo-decoding behind their profiles).
- G-104-02: An existing Compose install switches to the Flisk setup **without copying data**: same Docker volume names (`lychee_prod_mysql`, `lychee_ai_vision_embeddings`, `lychee_nsfw_queue`) and the same `./lychee/*` bind mounts: the generated file writes them as `../lychee/*` (relative to `.autogenerated/`, where Compose resolves them), and `docker compose config` resolves them to `<repo>/lychee/*`.
- G-104-03: Other services keep reaching each other by the Compose names (`lychee_api`, `lychee_db`), which are written as network aliases.
- G-104-04: `.autogenerated/docker-compose.yml` runs with plain Docker Compose and no Flisk (`docker compose --env-file .env -f .autogenerated/docker-compose.yml up -d`).
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
- G-104-05: Documentation in `docs/FLISK.md`, one pointer line in README, and a CI check that the generated file matches the `service.json` files.

## Non-Goals
- N-104-01: Replacing or editing `docker-compose.yaml`, `docker-compose.minimal.yaml`, the Dockerfiles or any image.
- N-104-02: Any change to application code, tests, API or UI.
- N-104-03: Production deployment or Kubernetes; Flisk does not deploy.

## Functional Requirements

| ID | Requirement | Success path | Validation path | Failure path | Telemetry & traces | Source |
|----|-------------|--------------|-----------------|--------------|--------------------|--------|
| FR-104-01 | One `service.json` per Compose service under `services/lychee/<name>/`, generated by `flisk import`. | Same image, env (Compose expressions such as `${DB_PASSWORD:-password}` kept as written), healthchecks incl. `start_period`, `depends_on` conditions, `tmpfs`, cap_add/cap_drop, security_opt, deploy limits, profiles, volumes. | `flisk config verify`; a per-service diff of `docker compose config --no-interpolate` for both files shows only the differences listed in FR-104-04. | Import notes list anything not carried over. | None (no app telemetry). | G-104-01 |
| FR-104-02 | Volumes keep their Docker names; bind mounts keep their host paths. | Generated file declares `mysql: name: lychee_prod_mysql` etc., and binds as `../lychee/*`. | Switch test: data written by the original stack is read by the generated one; `docker compose -f .autogenerated/docker-compose.yml config` shows bind sources `<repo>/lychee/uploads`, `/logs`, `/tmp`. | — | — | G-104-02 |
| FR-104-03 | Renamed services keep their Compose hostnames. | `lychee-api` answers as `lychee_api` (network alias). | `getent hosts lychee_api` inside `lychee_facial_recognition`. | — | — | G-104-03 |
| FR-104-04 | Generated Compose is committed and checked. | `.autogenerated/docker-compose.yml` (excepted from the `docker-compose.yml` ignore rule). | CI job runs `npx @flisk-sh/flisk-export@0.8.0 compose . --check` and `docker compose --env-file .env -f .autogenerated/docker-compose.yml config` (after `cp .env.example .env`). | CI fails when a `service.json` changed without regenerating. | — | G-104-04 |
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
| FR-104-05 | Documentation. | `docs/FLISK.md`: start with Flisk, start without Flisk, the volume/alias mapping, what differs. README: one line under *Docker*. | Links resolve. | — | — | G-104-05 |

## Non-Functional Requirements

| ID | Requirement | Driver | Measurement | Dependencies | Source |
|----|-------------|--------|-------------|--------------|--------|
| NFR-104-01 | No change to the existing Compose path. | Most installs use it. | `git diff` touches no existing file except README (one line) and `.gitignore` (one exception line). | — | G-104-01 |
| NFR-104-02 | Same reachability as Compose. | Self-hosters rely on `${APP_PORT:-8000}:8000`. | Port published on the same host address; checked with `docker ps` and from the LAN. | See *Pinned versions* | G-104-01 |
| NFR-104-03 | No secrets committed. | Security. | `.env` stays gitignored; only `${VAR}` expressions in `service.json`. | — | — |

## Branch & Scenario Matrix

| Scenario ID | Description / Expected outcome |
|-------------|--------------------------------|
| S-104-01 | Fresh clone, `cp .env.example .env`, then `flisk up lychee`: API healthy, `/` redirects to `/install/admin`. |
| S-104-02 | Fresh clone, `cp .env.example .env`, then `docker compose --env-file .env -f .autogenerated/docker-compose.yml up -d`: same as S-104-01. |
| S-104-03 | Existing install from `docker-compose.yaml`, `down` (volumes kept), then S-104-02: previous data is there. |
| S-104-04 | `service.json` edited without regenerating: CI check fails. |
| S-104-05 | `--profile nsfw` / `geo-decoding` / `phpmyadmin`: optional services start only when asked. |

## Test Strategy
- **Models / Actions, REST API, Artisan, Frontend:** not affected (N-104-02).
- **Docs/Contracts:** CI job from FR-104-04; manual switch test S-104-03 recorded in the PR with screenshots and logs.

Already verified on a scratch machine (macOS, Docker 29.5.2, flisk-import 0.14.0 / flisk-export 0.7.0; re-checked with 0.15.0 / 0.8.0): S-104-02 and S-104-03 pass (API healthy in 12 s on the original install's volumes, a marker row written by the original stack is read back, `lychee_api` resolves), and the installer page is identical to the one served by `docker-compose.yaml`.

## Pinned versions
The fields this relies on (`container.networkAliases`, `healthCheck.startPeriod`, `volumes[].name`, `profiles`, `envFile`, `container.tmpfs`) are in Flisk CLI **1.4.27** (released 2026-11-01). The files are produced and checked with fixed versions:

| Step | Command |
|------|---------|
| Import | `FLISK_IMPORT_PACKAGE=flisk-import@0.15.0 flisk import . --yes` |
| Export | `npx @flisk-sh/flisk-export@0.8.0 compose . --force` |
| CI check | `npx @flisk-sh/flisk-export@0.8.0 compose . --check` |
| Start | `flisk up lychee` (Flisk ≥ 1.4.27) |

`flisk export compose` is the same exporter run through the Flisk CLI; the spec uses the pinned `npx` form everywhere so CI does not depend on the installed CLI.

## Interface & Contract Catalogue

### Fixtures & Sample Data
| ID | Path | Purpose |
|----|------|---------|
| FX-104-01 | `services/lychee/*/service.json` | Flisk service definitions (generated by `flisk import`). |
| FX-104-02 | `.autogenerated/docker-compose.yml` | Compose generated from FX-104-01; do not edit. |
| FX-104-03 | `.flisk/project.json` | Flisk project file. |
19 changes: 19 additions & 0 deletions docs/specs/4-architecture/features/104-flisk-option/tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Feature 104 Tasks – Flisk Option

_Status: Draft_
_Last updated: 2026-11-01_

> Keep this checklist aligned with the feature plan increments. Stage tests before implementation, record verification commands beside each task, and prefer bite-sized entries (≤90 minutes).
> **Mark tasks `[x]` immediately** after each one passes verification—do not batch completions. Update the roadmap status when all tasks are done.

## Checklist
- [ ] T-104-01 – Generate `services/lychee/*/service.json` and `.flisk/project.json` with `FLISK_IMPORT_PACKAGE=flisk-import@0.15.0 flisk import . --yes` (S-104-01).
_Verification commands:_ `flisk config verify` (Flisk ≥ 1.4.27)
- [ ] T-104-02 – Generate and commit `.autogenerated/docker-compose.yml`; add the `.gitignore` exception (S-104-02, S-104-03).
_Verification commands:_ `npx @flisk-sh/flisk-export@0.8.0 compose . --force`; `cp .env.example .env`; `docker compose --env-file .env -f .autogenerated/docker-compose.yml config` with bind sources resolving to `<repo>/lychee/*`; per-service comparison against `docker-compose.yaml`
- [ ] T-104-03 – Write `docs/FLISK.md` and the README pointer line.
- [ ] T-104-04 – Add `.github/workflows/flisk.yml` (`npx @flisk-sh/flisk-export@0.8.0 compose . --check`; `cp .env.example .env` then `docker compose --env-file .env -f .autogenerated/docker-compose.yml config`) (S-104-04).
- [ ] T-104-05 – Record S-104-01 … 05 with screenshots and logs in the implementation PR.

## Notes / TODOs
None.
1 change: 1 addition & 0 deletions docs/specs/4-architecture/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ High-level planning document for Lychee features and architectural initiatives.

| Feature ID | Name | Status | Priority | Assignee | Started | Updated | Progress |
|------------|------|--------|----------|----------|---------|---------|----------|
| 104 | Flisk Option | Draft | Low | odykyi | 2026-11-01 | 2026-11-01 | Specification only, awaiting maintainer review (Q-104-01, Q-104-02). Optional `flisk up lychee` next to `docker-compose.yaml` (unchanged): `service.json` per service, generated `.autogenerated/docker-compose.yml` with the same volume names and the Compose names as network aliases. No app code change. See `features/104-flisk-option/`. |
| 103 | Album Load Speedup | In progress | High | ildyria | 2026-10-28 | 2026-10-28 | 26/27 tasks, drift gate in plan; v8 bulk album edit: icon headers with label tooltips, capture range tooltip on the creation date (FR-103-13 … 15, Q-103-05 A, v8 only); Q-103-04 C: stored `albums.is_recursive_nsfw` (ADR-103-01, FR-103-11/12), Timeline `buckets` 756 → 408 ms on identical data (battery run; NFR-103-03 AC check pending). Large albums, Timeline and the v8 photo view on struct-of-arrays. Backend: `Album::head`/HTML page read frame flag and header without loading photos (FR-103-01/02, `count` + `offset`, Q-103-03 B); smart-album queries scoped inside the id subquery, `buckets` by `COUNT(DISTINCT)` (FR-103-09). v8: lazy tile dates, navigation ids at adaptation, one-write page map, index-based layout, cached scrubber keys, one placeholder layout per bucket size (FR-103-03 … 06, 10); photo view loading/error state, video mounted with its URL, details window 10/5 and image preload 3/1 (FR-103-07/08). Scratch instance: album 7,000 photos first tile ≈1,070 → ≈656 ms, `head` 198 → 46 ms; Timeline 99,000 photos first tile ≈1,760 → ≈936 ms, window 620 → 24 ms. Not committed (owner commits). See `features/103-album-load-speedup/`. |
| 102 | Asset Endpoint Speedup | Testing | Medium | ildyria | 2026-10-20 | 2026-10-29 | Speed up `GET /api/v3/Asset`. Baseline: warm ≈9.2 ms and 15 queries per request, 11 of them from loading the album. No SE verification on the route (FR-102-01). Q-102-01 … 03 resolved Option A (FR-102-02 … 04), Q-102-04 resolved Option A (FR-102-05/06, ADR-102-01). Q-102-05 resolved Option A (FR-102-07, ADR-102-02), Q-102-06 resolved Option A (admins skip album checks, FR-102-02). Plan + 19 tasks, analysis gate passed, I1–I4 done (admin `/Asset` 4 queries incl. partial config, no SE verification; `Cache-Control: private, max-age=3600` + `304`; `GET /Albums/{album_id}/Photos/urls`; tile URL loader; grid tiles on direct URLs; `ETag` on `/Asset`; front-end stores cleared on login/logout, Q-102-11 resolved Option B, FR-102-08). 32/32 tasks, browser check and drift gate done; Q-102-07 open (admin temporary-link rule in `/Photos/urls`). See `features/102-asset-endpoint-speedup/`. |
| 101 | JPEG XL Support | Testing | Medium | ildyria | 2026-10-18 | 2026-10-22 | 14/14 tasks, drift gate passed. `.jxl` uploads accepted (original kept, signature detection); `size_variant_format` gains `jxl` (quality/lossless via `jxl:quality`/`jxl:distance`); `ImagickJxlCheck` diagnostics; Docker image builds ImageMagick 7.1.2-32 + imagick 3.8.1 with libjxl (ADR-101-01, +34 MB). Verified: scoped tests locally (134 passed, 15 JXL skips), Imagick suite inside the image, phpstan, php-cs-fixer, `vp check`, `vp run typecheck`. Awaiting commit. 2026-10-22: `Dockerfile-legacy` moved to the official `php:8.5-fpm-trixie` image (Sury had no PHP 8.5.12 for arm64) and gets the same JXL build from its own `imagemagick` stage (N-101-08 → FR-101-12, T-101-14). See `features/101-jxl-support/`. |
Expand Down