Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,7 @@ SYNC_PATH=/mnt/sync # Syncthing data directory
# Wallabag (read-it-later)
# Generate a random secret: openssl rand -hex 32
WALLABAG_SECRET=

# KOReader Sync Server — password hashing salt
# Generate with: openssl rand -hex 32
KOSYNC_PASSWORD_SALT=
19 changes: 19 additions & 0 deletions .light/sessions/2026-04-19-add-koreader-sync-server-execution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Execution Log: add-koreader-sync-server (2026-04-19)

Epic: epic add-koreader-sync-server

[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-1-docker-compose — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-1-docker-compose — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-1-docker-compose
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-2-env-example — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-2-env-example — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-2-env-example
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-3-homepage — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-3-homepage — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-3-homepage
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-4-readme — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-4-readme — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-4-readme
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-5-lint-verification — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-5-lint-verification — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-5-lint-verification
20 changes: 20 additions & 0 deletions .light/sessions/2026-04-19-add-koreader-sync-server.manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"session_date": "2026-04-19",
"topic": "add-koreader-sync-server",
"workflow_steps": ["research", "plan", "implement"],
"files_created": [],
"files_modified": [
"docker-compose.yml",
".env.example",
"homepage/config/services.yaml",
"README.md"
],
"gates": {
"RED": 0,
"GREEN": 5,
"VALIDATE": 0
},
"phases_completed": 5,
"total_phases": 5,
"test_suite_passed": true
}
51 changes: 51 additions & 0 deletions .light/sessions/2026-04-19-add-koreader-sync-server.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Session: Add KOReader Sync Server (2026-04-19)

## Research Summary

- **Image chosen:** `ghcr.io/nperez0111/koreader-sync:latest` — TypeScript/Bun/Hono, SQLite storage at `/app/data`, port 3000, built-in health check
- **Alternative considered:** `koreader/kosync` (official, Lua/OpenResty + Redis) — heavier, not chosen
- `PASSWORD_SALT` env var required for account creation; named Docker volume for SQLite persistence
- No Homepage widget available for kosync — link-only entry using `si-koreader` (Simple Icons)
- No `HOMEPAGE_VAR_*` references needed → lint script passes without homepage environment changes

## Plan Summary

**Goal:** Add `kosync` to the stack so KOReader devices sync reading positions to `https://kosync.woggles.work`.

**Phases:**

1. Docker Compose — add `kosync` service block + `kosync-data` named volume
2. Environment — add `KOSYNC_PASSWORD_SALT=` to `.env.example`
3. Homepage — add KOReader Sync link under Reading category in `services.yaml`
4. README — add KOReader Sync row to services table
5. Lint Verification — confirm `./scripts/lint-config.sh` exits 0

**Acceptance Criteria (all met):**

- `docker-compose.yml` includes `kosync` service with Traefik labels and `kosync-data` volume
- `.env.example` has `KOSYNC_PASSWORD_SALT=` with generation comment
- `homepage/config/services.yaml` has KOReader Sync link in Reading category
- `README.md` services table includes KOReader Sync row
- `./scripts/lint-config.sh` exits 0

## Execution Log

[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-1-docker-compose — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-1-docker-compose — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-1-docker-compose
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-2-env-example — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-2-env-example — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-2-env-example
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-3-homepage — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-3-homepage — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-3-homepage
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-4-readme — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-4-readme — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-4-readme
[DISPATCHED] group epic-add-koreader-sync-server-21z5 phase-5-lint-verification — agent type: no-test, mode: sync
[GATE PASS] group epic-add-koreader-sync-server-21z5 phase-5-lint-verification — GREEN gate passed
[CLOSED] group epic-add-koreader-sync-server-21z5 phase-5-lint-verification

## Outcome

All 5 phases completed. `./scripts/lint-config.sh` exits 0 — 6 HOMEPAGE*VAR*\* references and 11 .env.example vars all verified. All acceptance criteria met.
249 changes: 249 additions & 0 deletions .light/sessions/add-koreader-sync-server-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
# Plan: Add KOReader Sync Server

**tracker: yaks**

---

## Context

KOReader is an e-reader app (Kindle, Kobo, Android) that syncs reading progress across devices via a kosync-compatible server. The public service (`sync.koreader.rocks`) is a third-party dependency; this adds a self-hosted replacement.

Research findings:

- **Image:** `ghcr.io/nperez0111/koreader-sync:latest` — TypeScript/Bun/Hono, SQLite storage, port 3000, built-in health check at `GET /health`
- **Alternative considered:** `koreader/kosync` (official Lua/OpenResty + Redis) — heavier, less conventional; not chosen
- **Storage:** Named Docker volume `kosync-data` at `/app/data`; SQLite, no external DB needed
- **Auth:** `PASSWORD_SALT` env var required for account creation (generate via `openssl rand -hex 32`)
- **Routing:** Traefik on `proxy` network; no `ports:` mapping needed
- **Homepage:** Link-only entry (no widget API available); `si-koreader` icon via Simple Icons; Reading category already exists (contains Wallabag)
- **README:** Services table exists at lines 13–20; Wallabag was not added to it (out of scope here — we add KOReader Sync only)
- **lint-config.sh:** No `HOMEPAGE_VAR_*` references needed → script should pass without changes

---

## Goal

Add the `kosync` service to `docker-compose.yml` so KOReader devices can sync reading positions to the home server at `https://kosync.woggles.work`, and surface it on the Homepage dashboard.

---

## Acceptance Criteria

- [ ] `docker-compose.yml` includes `kosync` service with Traefik labels, `kosync-data` named volume, and `KOSYNC_PASSWORD_SALT` env var
- [ ] `kosync-data` volume declared at the compose root `volumes:` block
- [ ] `.env.example` has `KOSYNC_PASSWORD_SALT=` with a generation comment
- [ ] `homepage/config/services.yaml` has a KOReader Sync link in the Reading category
- [ ] `README.md` services table includes a KOReader Sync row
- [ ] `./scripts/lint-config.sh` exits 0 with no errors

---

## Files to Modify

| File | Change |
| ------------------------------- | ---------------------------------------------------------------- |
| `docker-compose.yml` | Add `kosync` service block; add `kosync-data` to root `volumes:` |
| `.env.example` | Add `KOSYNC_PASSWORD_SALT=` with generation comment |
| `homepage/config/services.yaml` | Add KOReader Sync link under Reading category |
| `README.md` | Add `KOReader Sync` row to services table |

---

## Implementation Phases

### Phase 1: Docker Compose — Add kosync service [no-test]

**Goal:** Wire the kosync container into the stack with Traefik routing and persistent storage.

**Tasks:**

- Add `kosync` service block after the Wallabag service in `docker-compose.yml`
- Add `kosync-data:` to the root `volumes:` block

**Verification:**

- [ ] `docker-compose config --quiet` exits 0 (compose file is valid)
- [ ] `kosync` service appears with `traefik.enable=true` label
- [ ] `kosync-data` volume is declared at root level

#### Agent Context

```
Files to modify:
- docker-compose.yml

Service block to add (after wallabag service):
kosync:
container_name: kosync
image: ghcr.io/nperez0111/koreader-sync:latest
environment:
- TZ=${TZ:-America/New_York}
- PASSWORD_SALT=${KOSYNC_PASSWORD_SALT:-}
volumes:
- kosync-data:/app/data
networks:
- proxy
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.kosync.rule=Host(`kosync.woggles.work`)"
- "traefik.http.routers.kosync.entrypoints=websecure"
- "traefik.http.routers.kosync.tls.certresolver=cloudflare"
- "traefik.http.services.kosync.loadbalancer.server.port=3000"

Root volumes block (currently has only `wallabag_images:`):
Add: kosync-data:

Verification command: docker-compose config --quiet
GREEN gate: exits 0
```

---

### Phase 2: Environment — Add KOSYNC_PASSWORD_SALT [no-test]

**Goal:** Document the required secret in `.env.example`.

**Tasks:**

- Add `KOSYNC_PASSWORD_SALT=` entry to `.env.example` with a comment

**Verification:**

- [ ] `KOSYNC_PASSWORD_SALT=` appears in `.env.example`
- [ ] Comment explains how to generate the value

#### Agent Context

```
Files to modify:
- .env.example

Entry to add (near other service secrets, e.g. after WALLABAG_SECRET block):

# KOReader Sync Server — password hashing salt
# Generate with: openssl rand -hex 32
KOSYNC_PASSWORD_SALT=

Verification: grep KOSYNC_PASSWORD_SALT .env.example
GREEN gate: line is present
```

---

### Phase 3: Homepage — Add KOReader Sync link [no-test]

**Goal:** Surface kosync on the dashboard under the Reading category.

**Tasks:**

- Add KOReader Sync link entry in `homepage/config/services.yaml` under Reading category

**Verification:**

- [ ] Entry appears under `- Reading:` in services.yaml
- [ ] `href` points to `https://kosync.woggles.work`

#### Agent Context

```
Files to modify:
- homepage/config/services.yaml

Current Reading category (line ~64):
- Reading:
- Wallabag:
href: https://wallabag.woggles.work
description: ...
icon: wallabag

Add after Wallabag:
- KOReader Sync:
href: https://kosync.woggles.work
description: KOReader reading progress sync
icon: si-koreader

No HOMEPAGE_VAR_* variables needed — link only, no widget block.

Verification: grep -A3 "KOReader" homepage/config/services.yaml
GREEN gate: href line is present
```

---

### Phase 4: README — Add services table row [no-test]

**Goal:** Keep the README services table accurate.

**Tasks:**

- Add KOReader Sync row to the services table in `README.md` (lines 13–20)

**Verification:**

- [ ] KOReader Sync row appears in the services table

#### Agent Context

```
Files to modify:
- README.md

Services table currently ends with:
| FileBrowser | https://files.woggles.work | File manager |

Add after FileBrowser row:
| KOReader Sync | https://kosync.woggles.work | Reading progress sync |

Verification: grep "KOReader" README.md
GREEN gate: line is present
```

---

### Phase 5: Lint Verification [no-test]

**Goal:** Confirm the lint script passes with no HOMEPAGE_VAR mismatches or missing .env.example vars.

**Tasks:**

- Run `./scripts/lint-config.sh`

**Verification:**

- [ ] Script exits 0
- [ ] No HOMEPAGE*VAR*\* reference errors
- [ ] No missing .env.example variable errors

#### Agent Context

```
Files to read:
- scripts/lint-config.sh (read-only — do not modify)
- docker-compose.yml
- .env.example
- homepage/config/services.yaml

Verification command: ./scripts/lint-config.sh
GREEN gate: exits 0 with no error output

If it fails: check for any accidentally added HOMEPAGE_VAR_* references
in services.yaml that are not wired in docker-compose.yml, or any
${VAR:-} patterns in docker-compose.yml missing from .env.example.
```

---

## Constraints & Considerations

- **No application code** — all phases are config/YAML edits; no tests beyond compose validation and lint
- **Named volume, not bind mount** — SQLite data lives in `kosync-data` Docker volume; no host path needed
- **No ports: mapping** — Traefik handles all ingress on the `proxy` network
- **Icon fallback** — `si-koreader` resolves via Simple Icons; if it doesn't render, `mdi-book-sync` is a safe fallback
- **Post-deploy KOReader setup** (out of scope for this PR): Settings → Progress sync → Custom sync server → `https://kosync.woggles.work`

## Out of Scope

- Adding Wallabag to the README services table (pre-existing omission; separate PR)
- KOReader app configuration documentation
- Monitoring/alerting for the kosync service
Loading
Loading