Ctrl K
ComunidadGuías…

GUIDE.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Knitting Library Deployment And Operations Guide

This guide collects the practical details that do not need to live in the project overview: deployment variants, first-run behavior, storage, backups, reverse proxy configuration, fail2ban, AI text recognition, and troubleshooting.

## Requirements

Use Docker Desktop, Docker Engine, or another Docker-compatible host, or follow [Running without Docker](#running-without-docker) for a native Python service with a built frontend and Poppler.

Docker Desktop is available from `https://www.docker.com/products/docker-desktop/`.

## Running With Docker Compose

From the folder containing `docker-compose.yml`:

```bash
docker compose up -d
```

Open `http://localhost:3000`.

On first launch, Knitting Library shows a setup screen for creating the first admin account. There are no default credentials. The first admin password must be at least 12 characters.

Existing installs are not changed. If your database already contains users, the normal login screen appears.

## Docker Desktop

In Docker Desktop, open the Compose section, point it at `docker-compose.yml`, and start the stack.

## Unraid Or Home Server Example

```yaml
services:
  app:
    image: zeetlex/knitting-library:latest
    restart: unless-stopped
    ports:
      - "3000:8080"
    environment:
      - PUID=99
      - PGID=100
      - TRUSTED_PROXIES=
    volumes:
      - /path/to/your/data:/data
      - /path/to/your/logs:/logs
```

`PUID` and `PGID` control host ownership for files written to `/data` and `/logs`. Docker Desktop users can usually set these to `0` or omit them.

The defaults remain `/data`, `/logs`, and `/app/frontend/build`. Override them with `KNITTING_DATA_DIR`, `KNITTING_LOG_DIR`, and `KNITTING_STATIC_DIR` respectively. Explicit values must be absolute paths; blank values keep defaults. If changing a container data/log path, change the corresponding volume target too. Native deployments must provide these variables through their service manager and configure Uvicorn output separately. See [Running without Docker](#running-without-docker) for native setup, log destinations, and password recovery, and [Moving existing data and custom Docker paths](#moving-existing-data-and-custom-docker-paths) for migration instructions.

## Running without Docker

The backend can run directly as an unprivileged Python service and serve both the API and the built frontend. Use Python 3.12, Node.js 20.19+ (or a compatible newer release) to build the frontend, and Poppler (`poppler-utils` on Debian/Ubuntu) for PDF processing. Node.js is only needed during the build.

Serve the app at the root of its own hostname. URL subpath hosting, a YunoHost package, and YunoHost SSO integration are not provided by these instructions.

From the repository root, create a virtual environment and build the frontend:

```bash
python3.12 -m venv .venv
.venv/bin/python -m pip install -r app/backend/requirements.txt
cd app/frontend
npm ci --legacy-peer-deps
npm run build
cd ../..
```

The build is written to `app/frontend/dist`. Configure these paths before starting the backend:

| Environment variable | Default | Contents |
|---|---|---|
| `KNITTING_DATA_DIR` | `/data` | `recipes.db`, `recipes/`, `yarns/`, `branding/` |
| `KNITTING_LOG_DIR` | `/logs` | `auth.log` and files read by Admin Logs |
| `KNITTING_STATIC_DIR` | `/app/frontend/build` | Built frontend, including `index.html` |

Unset or blank values use the defaults. Explicit paths must be absolute. The backend does not automatically load `.env`; export the values or supply them through your service manager. Restart the service after changing them. Data paths must be writable by the service account, and frontend files must be readable. Do not grant the service write access to the source code or frontend assets unless needed by your packaging workflow.

For example, with the repository at `/opt/knitting-library` and writable directories already created for your service account:

```bash
export KNITTING_DATA_DIR=/var/lib/knitting-library
export KNITTING_LOG_DIR=/var/log/knitting-library
export KNITTING_STATIC_DIR=/opt/knitting-library/app/frontend/dist
cd /opt/knitting-library/app/backend
/opt/knitting-library/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 8080 --access-log \
  >> /var/log/knitting-library/uvicorn.log 2>&1
```

Open the app through your reverse proxy and create the first admin account. Set `TRUSTED_PROXIES` to the proxy addresses/CIDRs when using forwarded HTTPS/client-IP headers; for a proxy on the same machine, `127.0.0.1/32,::1/128` is appropriate. See [the reverse proxy guide](#reverse-proxy). `ALLOWED_ORIGINS` is only needed when frontend and API origins differ. HTTPS is handled by the reverse proxy.

### systemd example

Create a dedicated `knitting-library` service account and provision `/var/lib/knitting-library` and `/var/log/knitting-library` with that account as owner (for example, mode `0750`). Install this unit as `/etc/systemd/system/knitting-library.service`, adjusting installation paths as needed:

```ini
[Unit]
Description=Knitting Library
After=network.target

[Service]
Type=simple
User=knitting-library
Group=knitting-library
WorkingDirectory=/opt/knitting-library/app/backend
Environment=KNITTING_DATA_DIR=/var/lib/knitting-library
Environment=KNITTING_LOG_DIR=/var/log/knitting-library
Environment=KNITTING_STATIC_DIR=/opt/knitting-library/app/frontend/dist
Environment=TRUSTED_PROXIES=127.0.0.1/32,::1/128
ExecStart=/opt/knitting-library/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 8080 --access-log
StandardOutput=append:/var/log/knitting-library/uvicorn.log
StandardError=append:/var/log/knitting-library/uvicorn.log
Restart=on-failure
UMask=0027

[Install]
WantedBy=multi-user.target
```

Run `sudo systemctl daemon-reload` and `sudo systemctl enable --now knitting-library`. The `append:` output destination requires systemd 240 or newer. Arrange log rotation through the host's logging tools. The Docker entrypoint is not used by this service.

`KNITTING_LOG_DIR` selects authentication logging and Admin Logs file locations; it does not redirect Uvicorn output. Configure your service manager as above for Admin Logs to show server output. Native deployments do not produce the Docker entrypoint's `supervisord.log`; that source may remain absent. If file-based authentication logging is unavailable, authentication events fall back to stderr.

For password recovery, use the same `KNITTING_DATA_DIR` as the service and run from the backend directory:

```bash
sudo -u knitting-library env KNITTING_DATA_DIR=/var/lib/knitting-library \
  /opt/knitting-library/.venv/bin/python -m app.cli reset-password admin
```

### Moving existing data and custom Docker paths

Changing `KNITTING_DATA_DIR` does not move data. Stop the service, back up the complete existing data directory, then copy or move `recipes.db`, `recipes/`, `yarns/`, `branding/`, and any SQLite sidecar files together to the new root. Set ownership for the service account, update the environment, restart, and verify users, recipes, yarn images, custom icons, and exports before removing the old copy. A wrong or empty destination can initialize a new database and make the existing library appear missing.

Existing Docker deployments need no configuration changes. The variables select paths **inside** the container. If overriding data or log paths in `.env`, update the Compose volume targets to match; for example, `KNITTING_DATA_DIR=/storage` requires `./data:/storage` instead of `./data:/data`. A custom static directory must contain the built frontend and be copied or mounted into the container. Changing only the host side of an existing bind mount does not require these variables.

## Mail Configuration

SMTP can be configured interactively under **Settings -> Admin -> Mail Server** or by deployment environment variables. Environment variables are useful for YunoHost, container orchestration, and other managed installations where mail credentials are provisioned during installation.

Non-blank environment values override only the matching database-backed admin settings. Overridden fields are displayed as read-only in the admin interface. Blank or unset variables leave the saved admin value in control, and removing an override restores that saved value. Email templates remain editable in the interface. Environment credentials are read at runtime and are not copied into the application database.

| Environment variable | Accepted values | Purpose |
|---|---|---|
| `KNITTING_MAIL_ENABLED` | `true` or `false` | Master switch for outgoing email |
| `KNITTING_MAIL_HOST` | Hostname or IP | SMTP server |
| `KNITTING_MAIL_PORT` | `1`-`65535` | SMTP port |
| `KNITTING_MAIL_USERNAME` | Text, optional | SMTP login username |
| `KNITTING_MAIL_PASSWORD` | Text, optional | SMTP login password; provide together with username |
| `KNITTING_MAIL_FROM` | Email or formatted sender | Sender shown on outgoing messages; defaults to username when omitted |
| `KNITTING_MAIL_SECURITY` | `none`, `starttls`, or `ssl` | SMTP transport security |
| `KNITTING_MAIL_ANNOUNCEMENTS_ENABLED` | `true` or `false` | Email published update notes to users who have an address |

Boolean values also accept `1`/`0`, `yes`/`no`, and `on`/`off`. Use `none` only for a trusted local connection, `starttls` for an SMTP connection upgraded with STARTTLS (commonly port 587), or `ssl` for implicit TLS (commonly port 465). Authentication is skipped when both username and password are absent. Supplying only one is rejected.

After changing mail variables, restart the application and use **Send Test** in the Mail Server admin page. Invalid SMTP configuration prevents mail from being sent but does not prevent Knitting Library from starting or prevent an editable email switch from being turned off. An invalid announcement toggle disables announcement emails without blocking password recovery or other transactional messages. Passwords are masked in the API and interface; protect any `.env` or service environment file because it still contains the real secret.

Both `starttls` and `ssl` verify the server certificate and hostname against trusted certificate authorities. Use a hostname covered by the certificate. For private mail servers, install the appropriate CA certificate in the application host/container trust store; do not disable certificate verification. Existing database `mail_tls` values remain supported: `true` selects STARTTLS and `false` selects implicit TLS. Legacy API updates to this field also update the explicit security mode, unless that mode is managed by the environment. When both fields are supplied, `mail_security` takes precedence.

### Docker Compose SMTP example

Copy `.env.example` to `.env` and set the values needed by your provider. For a STARTTLS service:

```dotenv
KNITTING_MAIL_ENABLED=true
KNITTING_MAIL_HOST=smtp.example.com
KNITTING_MAIL_PORT=587
KNITTING_MAIL_USERNAME=knitting@example.com
KNITTING_MAIL_PASSWORD=replace-with-app-password
KNITTING_MAIL_FROM="Knitting Library <knitting@example.com>"
KNITTING_MAIL_SECURITY=starttls
KNITTING_MAIL_ANNOUNCEMENTS_ENABLED=false
```

Then recreate the container so it receives the new environment:

```bash
docker compose up -d --force-recreate
```

If a password contains characters interpreted by Docker Compose, quote or escape it according to Compose `.env` syntax. Keep `.env` private; it is excluded by the repository's `.gitignore`.

### YunoHost SMTP example

YunoHost packages can enable mail for the application system user and pass the generated application name, `mail_pwd`, and sender address into the service environment. A typical local YunoHost configuration is:

```ini
Environment=KNITTING_MAIL_ENABLED=true
Environment=KNITTING_MAIL_HOST=127.0.0.1
Environment=KNITTING_MAIL_PORT=25
Environment=KNITTING_MAIL_USERNAME=knitting-library
Environment=KNITTING_MAIL_PASSWORD=generated-mail-password
Environment=KNITTING_MAIL_FROM=knitting-library@example.com
Environment=KNITTING_MAIL_SECURITY=none
```

The package should substitute its actual application id, generated mail password, and domain-derived sender. Store secrets in a root-readable environment file where practical instead of embedding them in a world-readable unit. If the YunoHost mail service is configured for STARTTLS on port 587, use `starttls` instead of `none`.

### Native service SMTP example

For the systemd unit shown above, place the variables in a file readable only by root and the service manager, for example `/etc/knitting-library/environment`, and add this under `[Service]`:

```ini
EnvironmentFile=/etc/knitting-library/environment
```

The environment file uses unquoted `KEY=value` entries unless systemd escaping is required. Run `sudo systemctl daemon-reload` and restart the service after changes.

## Mobile Installation

Open `http://YOUR-SERVER-IP:3000` in Safari on iPhone, then use Share -> Add to Home Screen.

Knitting Library is designed primarily for mobile/PWA use while still supporting desktop browsers.

## Interface Overview

- **Home dashboard**: overview counters, active projects, finished projects, and a Discover shelf that favors unfinished or not-started recipes.
- **Mobile navigation**: bottom navigation for Home, Recipes, Add, Inventory, and Menu, with a collapsible mode for more reading space.
- **Desktop navigation**: left sidebar with primary navigation and secondary links.
- **Add menu**: one entry point for recipe uploads, folder imports, and yarn additions.
- **Inventory**: yarn and thread samples, yarn stock, needles, tools, and notions in one place.
- **Settings**: appearance, account, data, and admin tools grouped into focused sections.

## Recipe Library

The recipe library uses a visual grid with thumbnails and adjustable card size. Recipes can be searched by name or tag and filtered by category, tag, or project status.

Supported imports include PDFs, individual images, multiple images, and folders. The Bulk Import Wizard works through folder imports one file at a time and saves progress automatically.

The recipe viewer supports scrollable pages, zoom, fullscreen, mobile swipe gestures, desktop arrow-key navigation, and cover image selection.

Image recipes include tools for crop, rotate, reorder, cover selection, and persistent quality adjustments. Quality edits can tune brightness/exposure, contrast, gamma, saturation, warmth, and sharpness, with an original-image restore option.

## Text Recognition And Review

Recipe pages can have a shared editable text version generated from scanned recipe images. Open a recipe, switch from **Original** to **Text version**, then create, edit, save, or regenerate the transcription.

Text recognition is configured by an admin under **Settings -> Admin -> AI / Text recognition**. The beta workflow uses a vision-capable OpenAI-compatible model and sends each recipe image or PDF page directly to AI for plain text transcription, one page at a time. Results are stored beside the matching original image for review.

An optional second cleanup pass can send raw page text back to AI for Markdown cleanup after scanning completes. This cleanup step is disabled unless an admin enables it.

Admins can preview and edit scan and cleanup prompts, tune max output tokens, configure scan and cleanup temperatures, and fetch model names from the configured OpenAI-compatible endpoint. Model fetching only lists models; generation settings are sent with each chat completion request.

Compatible providers include:

- OpenAI GPT vision-capable models, for example `https://api.openai.com/v1` plus an API key.
- Ollama, for example `http://host.docker.internal:11434/v1`.
- LM Studio, for example `http://host.docker.internal:1234/v1`.
- Other OpenAI-compatible local or hosted providers.

The current beta workflow is user-guided:

- AI vision sends each page image directly to the model, sequentially, and marks the job as ready for review.
- Optional AI cleanup can format raw page text before review.
- The Review view shows the original page beside editable draft text.
- Reviewers can accept pages, pause and resume, cancel the draft, insert a diagram crop, or crop a legend image.
- The diagram tool can move, resize, rotate and deskew the selected diagram crop, adjust the overlay grid, blur the background preview, and change overlay/generated grid line thickness.
- Completing review publishes one shared Markdown text version with reviewed text and saved diagram or legend image inserts.

The diagram editor saves diagram and legend inserts as images inside the reviewed Markdown text version. It does not parse knitting symbols into a final machine-readable chart or complete written instructions. Generation audit details, including provider tokens and estimated image input, are shown below the text version for review.

Generated text is persistent for the whole server, not private per user. AI output should always be checked against the original recipe, especially for old scans, Norwegian/English knitting abbreviations, stitch counts, unclear page photos, and diagram symbols.

## Annotations

Draw or highlight directly on recipe pages. Brush, opacity, and color are adjustable. Strokes are saved per page to the database and persist across sessions.

## Recipe Knitting Tools

Open **Verktøy** / **Tools** from the recipe action bar on mobile, or the wrench tool entry in recipe view, to use tools that stay attached to the current recipe and current user.

The **Counter** tab tracks the current row with plus and minus controls. Tapping the large counter finishes an `omgang`/round, increases the completed-round count, and resets the large row counter to `0`. Long-pressing the large counter undoes one completed round. Saved counts can include a name, category, and note.

The **Increase/decrease** tab calculates how to distribute stitch increases or decreases evenly from the current stitch count to the desired stitch count.

The **Notes** tab is one large recipe note sheet. It auto-saves through the backend, so notes are private to the signed-in user and specific to the recipe being viewed.

## Project Tracking

Recipes can be marked active or finished per user account. Other users can start and finish the same recipe separately without changing your own project state.

Starting a project can link a yarn and color variant, optionally deducting skeins from inventory. Finished projects can be rated for quality, difficulty, and result with optional notes.

The Home dashboard shows active and finished projects from every user, including who started or finished them. Opening someone else's active project opens the recipe with your own project state, so you can start it yourself. Admin users can view and manage all project sessions.

## Yarn And Inventory

The yarn catalogue stores material, yardage, needle size, tension, seller, price, and color variants. Each color can have a name, price, and photo. URL import is early beta and currently works best with Sandnes Garn.

Inventory tracks yarn/thread samples, yarn stock, needles, tools, and notions. Yarn/thread entries can be saved with quantity `0` as project-planning samples, or with stock quantity for physical skeins. Quantity changes have quick controls and a history log.

## Accounts, Appearance, And Admin Tools

User accounts use username/password login with bcrypt hashing, login rate limiting, optional TOTP two-factor authentication, and per-user settings.

Appearance options include light/dark mode, multiple color themes, per-user background choices, and per-user interface language.

The interface is available in English, Norwegian, Hungarian, French, German, and Spanish. Prices and inventory values can be shown in NOK, USD, GBP, HUF, or EUR.

The admin panel includes user management, API/container logs, SMTP mail configuration, AI text recognition settings, 2FA status management, update notes, and all-user project session inspection.

## Folder Structure

After first run, your directory will contain:

```text
your-folder/
  docker-compose.yml
  data/
    knitting.db       <- database
    recipes/          <- recipe files and thumbnails
    yarns/            <- yarn images
  logs/
    uvicorn.log       <- API requests and errors; also streamed to docker logs
    supervisord.log   <- container startup and watchdog events
    auth.log          <- failed logins, useful for fail2ban
```

Logs rotate automatically: 10 MB per file, 5 backups. Use `docker logs knitting-library` for startup, access, and crash output when the UI does not load. The Admin -> Logs screen reads the same persisted files from `./logs`.

## Backups And Restore

Copy the `data/` folder. It contains the database, recipe files, yarn images, annotations, session history, and settings.

To restore, copy `data/` back and restart the container.

Back up before updating, especially while the project is in beta.

## Security Details

| Area | Status |
|---|---|
| Password hashing | bcrypt, rounds=12 |
| Login rate limiting | 10 attempts per 15 min per IP, plus fail2ban support |
| Two-factor authentication | TOTP |
| Session expiry | 30 days; 2FA challenges expire in 5 minutes |
| Session storage | HttpOnly SameSite cookies; legacy `X-Session-Token` still accepted for compatibility |
| CSRF | CSRF token required for cookie-authenticated write requests |
| File upload validation | Magic-byte checks plus size limits: 50 MB PDF, 20 MB image |
| CORS | Same-origin only, set `ALLOWED_ORIGINS` if needed |
| Security headers | CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy |
| API documentation | Disabled in production |
| SQL injection | Parameterised queries throughout |
| Path traversal | Filename sanitisation on uploads |
| SSRF | Yarn URL scraper validates DNS/IPs and redirect hops |
| Frontend dependencies | Vite build with committed npm lockfile |
| HTTPS | Not built in; use a reverse proxy |

Recommended deployment options, in order of preference:

- Home network only.
- VPN access, such as Tailscale or WireGuard.
- Reverse proxy with HTTPS.

Direct port forwarding to the internet is not recommended.

The author takes no responsibility for data loss, unauthorised access, or issues arising from how you deploy this application.

## Reverse Proxy

If the app runs behind a reverse proxy, configure `TRUSTED_PROXIES` so the app only trusts `X-Forwarded-For` and `X-Forwarded-Proto` from your proxy. Use the proxy container IP or Docker network CIDR:

```yaml
environment:
  - TRUSTED_PROXIES=172.16.0.0/12
```

For Nginx Proxy Manager, add this in the proxy host Advanced tab:

```nginx
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
```

For Caddy:

```caddyfile
knitting.example.com {
  reverse_proxy knitting-library:8080 {
    header_up X-Forwarded-For {remote_host}
    header_up X-Forwarded-Proto {scheme}
  }
}
```

Pin image versions for production when possible. `latest` is convenient for testing, but a version tag plus a backup before updating is safer.

## Fail2ban Optional Setup

If the app is exposed through a reverse proxy, fail2ban can block IPs that repeatedly fail to log in.

The app writes failed login and bad 2FA attempts to `logs/auth.log`. When using a proxy, set `TRUSTED_PROXIES` as described above.

Example log line:

```text
2025-01-15 14:23:45 AUTH_FAIL ip=1.2.3.4 user=admin reason=bad_password
```

Filter, `filter.d/knitting-library.conf`:

```ini
[Definition]
failregex = ^%Y-%m-%d %H:%M:%S AUTH_FAIL ip=<HOST>\b
ignoreregex =
datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S
```

Jail, `jail.d/knitting-library.conf`:

```ini
[knitting-library]
enabled  = true
filter   = knitting-library
logpath  = /path/to/your/logs/auth.log
maxretry = 5
findtime = 600
bantime  = 3600
action   = iptables-multiport[name=knitting-library, port="80,443,3000", protocol=tcp]
```

Reload fail2ban after placing the files:

```bash
fail2ban-client reload
fail2ban-client status knitting-library
```

## Troubleshooting

| Problem | Fix |
|---|---|
| Blank page or app will not load | Make sure Docker is running and the container is started. |
| Not logged in error | Refresh the page; the session may have expired. |
| PDF thumbnail not showing | Large PDFs can take time to process. |
| Cannot reach it on phone | Use the server IP, not `localhost`, and make sure the phone is on the same network. |
| Annotations not saving | Check that the `./data` volume is mounted correctly. |
| URL import did not fill everything | URL import is early beta; fill missing fields manually. |
| Live logs show nothing | Check `docker logs knitting-library` first, then confirm `./logs:/logs` is mounted. |
| Requests show the same IP | Configure forwarded headers and `TRUSTED_PROXIES`. |
| Port 8080 shows nothing | Check container logs with `docker logs knitting-library`. |

## Updating

Before updating, back up `data/`.

With Compose:

```bash
docker compose pull
docker compose up -d
```

If you maintain a pinned image tag, update the tag in `docker-compose.yml`, then pull and restart.