# Project pack: Leantime @ 8464a2e

Facts about **Leantime** for an AI following the [BespokeAI handover guide](https://handoff.bespokeai.software/guide/v1.md). This pack is pinned to one version and never changes after publication.

> Leantime is a project planner for people who don't think of themselves as project managers. A "My Work" home page shows today's to-dos and calendar, and each project has boards, lists, a timeline, goals, idea boards, documents and timesheets. It was designed with ADHD, dyslexia and autism in mind, with a readable font option and gentle nudges. Use it for a house move, a small business or a volunteer group, on your own server.

## Version and source
- Repository: https://github.com/Leantime/leantime
- Pinned commit: `8464a2eac9f6206f85e03269909c5227ea12f8ea`. Use exactly this version.
- Get it: `git clone https://github.com/Leantime/leantime leantime && cd leantime && git checkout 8464a2eac9f6206f85e03269909c5227ea12f8ea`
- Or download a zip: https://github.com/Leantime/leantime/archive/8464a2eac9f6206f85e03269909c5227ea12f8ea.zip
- Official docs: https://docs.leantime.io
- Licence: **AGPL-3.0-only**. Free to use and change. If you run a changed version that other people use over the internet (not just you or your household), you must offer them your source code under the same licence. Private use has no extra obligations. Plugins in app/Plugins/ can carry other licences, including Leantime's paid ones.

## Running it
- Easiest:

  ```sh
  docker network create leantime-net
  docker run -d --name mysql_leantime --network leantime-net -e MYSQL_ROOT_PASSWORD=change-me-root -e MYSQL_DATABASE=leantime -e MYSQL_USER=lean -e MYSQL_PASSWORD=change-me -v leantime-db:/var/lib/mysql mysql:8.4 --character-set-server=UTF8MB4 --collation-server=UTF8MB4_unicode_ci
  docker run -d --name leantime --network leantime-net -p 8080:8080 -e LEAN_DB_HOST=mysql_leantime -e LEAN_DB_USER=lean -e LEAN_DB_PASSWORD=change-me -e LEAN_DB_DATABASE=leantime -e LEAN_EMAIL_RETURN=you@example.com -e LEAN_SESSION_PASSWORD="$(openssl rand -hex 32)" -v leantime-userfiles:/var/www/html/userfiles -v leantime-public:/var/www/html/public/userfiles -v leantime-plugins:/var/www/html/app/Plugins leantime/leantime:latest
  # Wait for MySQL to start, then open http://localhost:8080/install to create your account.
  # Change both passwords before real use. The official compose file is in the Leantime/docker-leantime repository.
  ```

- Needs: Docker, or PHP 8.2+ with the extensions listed in the README, Apache or Nginx, and MySQL 8.0+ or MariaDB 10.6+, For development, Docker, make, Composer, Node.js and npm
- Develop: `make clean build && make run-dev   # app on http://localhost:5080 with MySQL, MailDev and S3Ninja`
- Test: `make unit-test   # make acceptance-test needs the Docker dev stack`
- Check/lint: `make test-code-style && make phpstan`
- Build: `make build-dev   # installs dependencies and builds the JavaScript and CSS`
- Stack: php, javascript, css (Laravel components, Blade, HTMX, jQuery, Tailwind CSS, Laravel Mix). Difficulty for a non-developer with an AI: **moderate**. Site name, logo, colours, themes, fonts, to-do statuses and chat notifications are settings. Code is organised by feature in app/Domain/<Feature>/ (controllers, services, repositories, templates), but it is mid-migration: old .tpl.php and newer Blade templates, jQuery and HTMX sit side by side, and the JavaScript needs a webpack build. CLAUDE.md explains the patterns.

## The project's own AI instructions
Read these in the repository before changing code: `CLAUDE.md`, `CONTRIBUTING.md`.

## Customisation points (settings → extend → code)
- **company-branding** [settings]: Your site name, logo and brand colours, plus the telemetry switch. → `Company settings (app/Domain/Setting/Templates/editCompanySettings.blade.php) or LEAN_SITENAME, LEAN_LOGO_PATH, LEAN_PRIMARY_COLOR, LEAN_SECONDARY_COLOR`
- **personal-look** [settings]: Each person picks a theme, light or dark mode, a colour scheme and a font, including the very readable Atkinson Hyperlegible. → `My profile → settings (app/Domain/Users/Templates/editOwn.blade.php), themes in public/theme/`
- **todo-statuses** [settings]: Name your board columns and their colours, e.g. Ideas, This week, Waiting on someone, Done. → `Project settings → To-Do statuses (app/Domain/Projects/Templates/showProject.blade.php)`
- **language-and-region** [settings]: Interface language and time zone per person; defaults with LEAN_LANGUAGE and LEAN_DEFAULT_TIMEZONE. → `Profile language and time zone; 45 language files in app/Language/`
- **chat-notifications** [extend]: Send project updates to a Slack, Mattermost, Discord or Zulip channel. → `Project settings → Integrations (app/Domain/Projects/Templates/showProject.blade.php)`
- **csv-import** [extend]: Bring in tasks from a spreadsheet or another tool. → `Import from CSV (app/Domain/CsvImport/)`
- **api** [extend]: Create and read to-dos, projects, goals and more from scripts or other apps. → `JSON-RPC API at /api/jsonrpc with an API key created by an admin (app/Domain/Api/Controllers/Jsonrpc.php, ApiKey.php); docs at docs.leantime.io/api/usage`
- **plugins** [extend]: Add new pages, menu items and event listeners in a plugin that survives updates. → `app/Plugins/<Name>/ (Plugins page in the app, app/Domain/Plugins/); guide at docs.leantime.io/development/plugin-development`
- **feature-screens** [code]: Change or add screens. New partials should use Blade and HTMX, as CLAUDE.md describes. → `app/Domain/<Feature>/Controllers/, Services/, Repositories/, Templates/ (e.g. app/Domain/Tickets/, app/Domain/Dashboard/)`
- **text** [code]: Change wording, e.g. call "To-Dos" "Jobs". → `app/Language/en-US.ini (other languages are managed on Crowdin)`

## Must keep working
- Existing projects, to-dos, comments, files and timesheets. Back up the database and userfiles first.
- Database changes need a migration that /update can run; never edit the database by hand.
- Project access. People must only see projects they are assigned to.
- The JSON-RPC API. Service methods are the API, so renaming or removing public service methods breaks integrations.
- Keep plugins in app/Plugins/ (a mounted volume in Docker) or they disappear after a restart.

## Staying updatable
Settings, chat integrations, the API and plugins cover most needs; plugins survive updates. Read CLAUDE.md before code changes. Upstream accepts bug-fix pull requests but asks you to discuss new features on Discord first, requires a signed CLA, and takes translations only through Crowdin.

## Data, costs and safety
- Personal data: **yes**. Stored in: A MySQL or MariaDB database for projects, to-dos, comments, goals and timesheets; uploaded files in userfiles/ (or S3); plugins in app/Plugins/. Back up the database and the userfiles volumes before updates or code changes. When you update, Leantime sends you to /update to migrate the database. In Docker, make sure MySQL uses a named volume, or an update deletes your data.
- Service: Email (SMTP) (optional, free with most providers): Invitations, password resets and notification emails. Without an app URL and email, invites are not sent.
- Service: Slack, Mattermost, Discord or Zulip (optional, free): Post project updates into a chat channel via a webhook, set per project.
- Service: S3 or compatible storage (optional, pay-per-use): Keep uploaded files outside the server (LEAN_USE_S3).
- Service: Leantime telemetry and news (optional, free): Sends a daily anonymous usage summary to telemetry.leantime.io and fetches product news. Both on by default; switch off with LEAN_ALLOW_TELEMETRY=false and LEAN_NEWS_ENABLED=false.
- Service: Leantime marketplace plugins (optional, paid licences): Extra features such as more integrations, sold separately. Not needed for the open-source features.
- Setting `LEAN_DB_HOST`: Your MySQL or MariaDB server. Goes with LEAN_DB_USER, LEAN_DB_DATABASE and LEAN_DB_PORT.
- Setting `LEAN_DB_PASSWORD` (**secret**: the person enters it themselves, never in chat): Database password. Never paste it into an AI chat.
- Setting `LEAN_SESSION_PASSWORD` (**secret**: the person enters it themselves, never in chat): Long random text used to protect logins. Replace the sample value. Never paste it into an AI chat.
- Setting `LEAN_APP_URL`: The address you open Leantime at, e.g. https://plans.example.com. Strongly recommended; invitation and password-reset emails need it.
- Setting `LEAN_EMAIL_RETURN`: The "from" address for emails. Set LEAN_EMAIL_USE_SMTP and the LEAN_EMAIL_SMTP_* variables to send real email.
- Setting `LEAN_EMAIL_SMTP_PASSWORD` (**secret**: the person enters it themselves, never in chat): Password for your email account. Never paste it into an AI chat.
- Setting `LEAN_SITENAME`: The name shown in the app (can also be changed in Company settings).
- Setting `LEAN_PRIMARY_COLOR`: Main brand colour (hex). LEAN_SECONDARY_COLOR, LEAN_LOGO_PATH and LEAN_DEFAULT_THEME go with it.
- Setting `LEAN_LANGUAGE`: Default language, e.g. en-GB. LEAN_DEFAULT_TIMEZONE sets the time zone.
- Setting `LEAN_ALLOW_TELEMETRY`: Set to false to never send the anonymous daily usage summary.
- Setting `LEAN_NEWS_ENABLED`: Set to false to stop fetching Leantime news (for offline installs).
- Setting `LEAN_S3_SECRET` (**secret**: the person enters it themselves, never in chat): Only with LEAN_USE_S3=true, together with LEAN_S3_KEY, LEAN_S3_BUCKET and LEAN_S3_REGION. Never paste it into an AI chat.
- Telemetry and the news feed are on by default. Set LEAN_ALLOW_TELEMETRY=false and LEAN_NEWS_ENABLED=false if you want nothing sent to Leantime.
- Replace the sample LEAN_SESSION_PASSWORD and database passwords, set LEAN_APP_URL, and use HTTPS if it is on the internet.
- Only install plugins from sources you trust. They run with full access to your data.
- Never paste database, email, S3 passwords or API keys into an AI chat.

---

# Customising Leantime

Leantime is a PHP app built from Laravel components, organised by feature under `app/Domain/`. **Branding, themes, fonts, board columns and chat notifications are all settings**, and plugins let you add features without a fork. Try those first.

> The code is mid-way through two migrations (old `.tpl.php` templates to Blade, jQuery to HTMX), so you will see mixed patterns. Upstream `CLAUDE.md` explains which to follow.

## Level 1: Settings (no code)
- **Name, logo and colours:** Company settings (admins). Or set `LEAN_SITENAME`, `LEAN_LOGO_PATH`, `LEAN_PRIMARY_COLOR`, `LEAN_SECONDARY_COLOR` in the environment.
- **Personal look:** each person's profile settings: theme (`public/theme/default` or `minimal`), light or dark mode, colour scheme and font, including Atkinson Hyperlegible for easier reading.
- **Board columns:** Project settings → To-Do statuses. Rename, recolour and reorder the columns for each project.
- **Language and time zone:** per person in their profile, defaults from `LEAN_LANGUAGE` and `LEAN_DEFAULT_TIMEZONE`.
- **Privacy:** `LEAN_ALLOW_TELEMETRY=false` stops the anonymous daily usage report; `LEAN_NEWS_ENABLED=false` stops the news feed.
- **Email:** `LEAN_APP_URL`, `LEAN_EMAIL_RETURN`, `LEAN_EMAIL_USE_SMTP` and `LEAN_EMAIL_SMTP_*`. Without an app URL, invitations and password resets aren't sent.
- All options are listed in `config/sample.env`. In Docker, pass them as `-e` variables.

## Level 2: Extend (no fork)
- **Chat integrations:** Project settings → Integrations. Paste a Slack, Mattermost or Discord webhook URL, or Zulip bot details, to get project updates in a channel.
- **CSV import:** bring in to-dos from a spreadsheet (`app/Domain/CsvImport/`).
- **JSON-RPC API:** `POST /api/jsonrpc` with an API key. Methods follow `leantime.rpc.<domain>.<service>.<method>`, e.g. tickets and projects. Docs: https://docs.leantime.io/api/usage
- **Plugins:** a folder in `app/Plugins/` (mount it as a volume in Docker). Plugins can register routes, menu items, templates and event listeners. Guide: https://docs.leantime.io/development/plugin-development. Paid plugins are sold on marketplace.leantime.io.

## Level 3: Code
Read upstream `CLAUDE.md` and `CONTRIBUTING.md` first (PSR-12).

| Change | Where |
|---|---|
| A feature's screens | `app/Domain/<Feature>/Controllers/` + `Templates/` (prefer `.blade.php` for new work) |
| Partial updates without reload | `app/Domain/<Feature>/Hxcontrollers/` (HTMX) |
| Business logic (also the API) | `app/Domain/<Feature>/Services/` |
| Database access | `app/Domain/<Feature>/Repositories/` |
| My Work home page and widgets | `app/Domain/Dashboard/`, `app/Domain/Widgets/` |
| To-dos, boards, milestones | `app/Domain/Tickets/` |
| Shared layouts and components | `app/Views/Templates/`, themes in `public/theme/` |
| Styles and scripts | `public/assets/css/`, `public/assets/js/`, built with `make build-dev` (Laravel Mix, Tailwind) |
| Text | `app/Language/en-US.ini` (other languages come from Crowdin) |

## Running locally
- **Just use it (Docker):**
  1. `docker network create leantime-net`
  2. Start MySQL 8.4 on that network with a `leantime` database and user (see the quickstart in `bespoke.yaml`, or the official compose file in the `Leantime/docker-leantime` repository).
  3. Start `leantime/leantime:latest` with `LEAN_DB_HOST`, `LEAN_DB_USER`, `LEAN_DB_PASSWORD`, `LEAN_DB_DATABASE`, `LEAN_SESSION_PASSWORD` and volumes for `userfiles`, `public/userfiles` and `app/Plugins`, on port 8080.
  4. Open http://localhost:8080/install and create the first account.
- **Develop:** with Docker, make, Composer and npm installed, run `make clean build`, then `make run-dev`. The app is at http://localhost:5080, with MySQL, MailDev (catches emails) and S3Ninja; their ports are random, so look them up with `docker compose --file .dev/docker-compose.yaml port maildev 8081`.
- **Check:** `make test-code-style`, `make phpstan`, `make unit-test`; `make acceptance-test` runs browser tests in Docker.

## Pitfalls
- Back up the MySQL database and the userfiles volumes before updating. In Docker, MySQL must use a named volume or an update wipes it.
- After an update, open `/update` (or run `php bin/leantime system:update`) to migrate the database.
- Every public service method is reachable over the API. Don't put admin-only logic in a service without a permission check.
- Don't edit language files other than `en-US.ini` directly; upstream syncs them from Crowdin.

---
Machine-readable: [bespoke.yaml](https://handoff.bespokeai.software/p/leantime/8464a2e/bespoke.yaml) · Agent skill: [SKILL.md](https://handoff.bespokeai.software/p/leantime/8464a2e/SKILL.md)
