diff --git a/software-development/project-management/README.md b/software-development/project-management/README.md new file mode 100644 index 0000000..922817f --- /dev/null +++ b/software-development/project-management/README.md @@ -0,0 +1,48 @@ +# Project Management + +Tools for tracking the progress of projects and their tasks. + +## Leantime +This is built for creatives and has a lot of visual polish and (in my opinion) a very cluttered view. + +Pros +- Design is pleasant to look at, feels somewhat modern. + +Cons +- This is focused more towards personal time management rather than project management. Cannot hide certain modules per project. All features really rely around tracking time, less suited for one off grab-bag task items. + +## Openproject +Fully featured project managment software, with a plain design. + +Pros +- Many customization options, such as removing modules from projects for features you don't use. Quite a lot of features in general. + +Cons +- UI looks old, not a great fit for mobile browsing. + +## Plane +Modern design, nearly best in class. Has sprints ( + +Pros +- Best polish for UI of the options I've tried. + +Cons +- Mobile usage gated behind $6/seat paywall. + +## Planka +Blah blah + +Pros +- + +Cons +- + +## Example +Blah blah + +Pros +- + +Cons +- diff --git a/software-development/project-management/leantime/.env.example b/software-development/project-management/leantime/.env.example new file mode 100644 index 0000000..814cb14 --- /dev/null +++ b/software-development/project-management/leantime/.env.example @@ -0,0 +1,30 @@ +# Public hostname (no scheme) +DOMAIN=leantime.example.com + +# Full base URL (include scheme) — used by Leantime for cookies and links +LEAN_APP_URL=https://leantime.example.com + +# Pin a version, or leave unset for :latest +LEAN_VERSION=latest + +# Session salt — generate with `openssl rand -base64 32` +LEAN_SESSION_PASSWORD= +LEAN_SESSION_SECURE=true + +# Timezone +LEAN_DEFAULT_TIMEZONE=America/Los_Angeles + +# Database +MYSQL_ROOT_PASSWORD= +LEAN_DB_DATABASE=leantime +LEAN_DB_USER=leantime +LEAN_DB_PASSWORD= + +# Email (optional; leave LEAN_EMAIL_USE_SMTP=false to use php mail()) +LEAN_EMAIL_RETURN= +LEAN_EMAIL_USE_SMTP=false +LEAN_EMAIL_SMTP_HOSTS= +LEAN_EMAIL_SMTP_USERNAME= +LEAN_EMAIL_SMTP_PASSWORD= +LEAN_EMAIL_SMTP_SECURE= +LEAN_EMAIL_SMTP_PORT= diff --git a/software-development/project-management/leantime/.gitignore b/software-development/project-management/leantime/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/software-development/project-management/leantime/.gitignore @@ -0,0 +1 @@ +.env diff --git a/software-development/project-management/leantime/README.md b/software-development/project-management/leantime/README.md new file mode 100644 index 0000000..49b0a34 --- /dev/null +++ b/software-development/project-management/leantime/README.md @@ -0,0 +1,21 @@ +# Leantime +Open source goals-focused project management system. + +## Setup +1. Copy `.env.example` to `.env` and fill out all values. Use `openssl rand -base64 32` for `LEAN_SESSION_PASSWORD` and DB passwords. +2. Start the stack: `docker compose up -d` +3. Open `https://${DOMAIN}/install` once to run the first-time installer; it will create the schema and the initial admin user. + +## Runbook + +Single Command +```bash +docker compose down && docker system prune && docker compose up -d && docker logs -f leantime +``` + +**Fix data folder permissions (run on first boot / when adding a new host volume)** +The PHP container runs as `www-data` (UID/GID 1000) and needs to own everything except `db/` (MySQL manages its own). +``` +sudo chown -R 1000:1000 /pwspool/software/leantime/{public_userfiles,userfiles,plugins,logs} +``` + diff --git a/software-development/project-management/leantime/docker-compose.yml b/software-development/project-management/leantime/docker-compose.yml new file mode 100644 index 0000000..00f443c --- /dev/null +++ b/software-development/project-management/leantime/docker-compose.yml @@ -0,0 +1,77 @@ +networks: + traefik: + external: true + leantime: + driver: bridge + +services: + + # ── Database ──────────────────────────────────────────────────────────────── + + leantime-db: + image: mysql:8.4 + container_name: leantime-db + restart: always + networks: + - leantime + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + MYSQL_DATABASE: ${LEAN_DB_DATABASE} + MYSQL_USER: ${LEAN_DB_USER} + MYSQL_PASSWORD: ${LEAN_DB_PASSWORD} + command: --character-set-server=UTF8MB4 --collation-server=UTF8MB4_unicode_ci + volumes: + - /pwspool/software/leantime/db:/var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + interval: 30s + timeout: 10s + retries: 5 + + # ── Application ───────────────────────────────────────────────────────────── + + leantime: + image: leantime/leantime:${LEAN_VERSION:-latest} + container_name: leantime + restart: always + networks: + - leantime + - traefik + depends_on: + leantime-db: + condition: service_healthy + security_opt: + - no-new-privileges:true + cap_add: + - CAP_CHOWN + - CAP_SETGID + - CAP_SETUID + environment: + LEAN_APP_URL: ${LEAN_APP_URL} + LEAN_SESSION_PASSWORD: ${LEAN_SESSION_PASSWORD} + LEAN_SESSION_SECURE: ${LEAN_SESSION_SECURE:-true} + LEAN_DB_HOST: leantime-db + LEAN_DB_PORT: 3306 + LEAN_DB_DATABASE: ${LEAN_DB_DATABASE} + LEAN_DB_USER: ${LEAN_DB_USER} + LEAN_DB_PASSWORD: ${LEAN_DB_PASSWORD} + LEAN_DEFAULT_TIMEZONE: ${LEAN_DEFAULT_TIMEZONE:-America/Los_Angeles} + LEAN_EMAIL_RETURN: ${LEAN_EMAIL_RETURN} + LEAN_EMAIL_USE_SMTP: ${LEAN_EMAIL_USE_SMTP:-false} + LEAN_EMAIL_SMTP_HOSTS: ${LEAN_EMAIL_SMTP_HOSTS} + LEAN_EMAIL_SMTP_USERNAME: ${LEAN_EMAIL_SMTP_USERNAME} + LEAN_EMAIL_SMTP_PASSWORD: ${LEAN_EMAIL_SMTP_PASSWORD} + LEAN_EMAIL_SMTP_SECURE: ${LEAN_EMAIL_SMTP_SECURE} + LEAN_EMAIL_SMTP_PORT: ${LEAN_EMAIL_SMTP_PORT} + volumes: + - /pwspool/software/leantime/public_userfiles:/var/www/html/public/userfiles + - /pwspool/software/leantime/userfiles:/var/www/html/userfiles + - /pwspool/software/leantime/plugins:/var/www/html/app/Plugins + - /pwspool/software/leantime/logs:/var/www/html/storage/logs + labels: + - traefik.enable=true + - traefik.docker.network=traefik + - traefik.http.routers.leantime.rule=Host(`${DOMAIN}`) + - traefik.http.routers.leantime.tls=true + - traefik.http.routers.leantime.tls.certresolver=lets-encrypt + - traefik.http.services.leantime.loadbalancer.server.port=8080