之前使用的是Nextcloud上面的Task和Deck。渐渐的发现NC还是一如既往的不好使。于是又开始搜刮自托管的TODO方案。Vikunja似乎可以满足需要,搞一个试一试。
用了一段时间之后的体验-2024-01-07
一个对于个人使用来讲已经算得上完备的Todo。但是对于团队项目管理还有不足。所以并不能说是project management的方案(尽管Gantt chart以及kanban都是有的)。
一个遗憾是没有offline模式。这个对于一个Todo来讲相当可惜。坐飞机的时候没有办法愉快的思考人生了(穷人没有飞机Wifi)。
另一个遗憾是不支持定期重复。这个对于个人用户来讲确实有些遗憾。
Vikunja简介
The open-source, self-hostable to-do app | Vikunja
其实就是一个TODO list。但是确实包含一些相对已经比较高端了的 Project Management的功能。
个人认为,一个好的TODO list,应该包括几乎所有的Project Management的功能,但是可以在Org chart方面没那么强大。同时,应该做到兼顾最基础的功能的易用性,和当情况变复杂时,充足的扩展性。
同时,一个TODO的界面需要有一定的颜值。否则界面不好看,本来就拖延症,更不想干活了。目前来看呢,Vikunja还算是比较符合这些要求了吧。
Vikunja的优点
Vikunja默认的界面就可以很方便的添加新的Task,然后也可以把目前没有完成的Task显示出来,这方面跟一个最基本的TODO没什么区别。
同时也允许添加 “project”,用来分类管理“一类“ task。相当于文件夹的概念。之所以说是“文件夹“,是因为这里不仅是 single parent的关系(其实也就是category,通常这种都只有一个父节点),而且是可以嵌套的。比如我这里就是 Home Server → Hardware → ZFS Mirror NVME pool。这里肯定有小伙伴说,这平时根本就用不上。但这就是我觉得很重要的一点,一个工具的扩展性还是很重要的,我可以先不用,但是当我要用的时候,你如果没有,那我就很难受了。
对于不适合“单一父节点“关系的情况,Vikunja也提供了 Label,跟tag差不多。这里的label应该就是相当于单独一个Key,并不会再附加Value了。实际使用中应该是绝对够用了。(如果是key + value,那更贴切的叫法应该是attribute,不过我总是受GCP的影响,看到Label总觉得就是个string KV pairs)
Vikunja还支持多人合作。这又是一个,普通用户觉得可以没有,但是一但发现有需要,而功能又没有,就开始觉得难受的功能。
Vikunja还支持每天发送一封Email简报,提醒你Overdue的task。这部分功能目前还没有配置,但是我觉得应该还是很有用的,之后应该会配置上。
针对一个Task,Vikunja提供了丰富的Metadata,满足各种需求。
举一些例子:
- Progress
- 这个其实会比很多人想象中的更常用。比如,有一件task,创建了之后,发现其工作量远远大于一开始的估计。这个时候怎么办?拆成小的subtask自然是可以的。可是有的时候,并不能或者不想给一个task做分解,因为太费脑子(有时相当于做一个小的design了),而只是这个工作需要多分成几天完成。这个时候用progress,就非常顺手。
- Relation
- 上面提到的subtask的概念,这自然是非常常用的。Vikunja里面自然也是支持的。
- Start Date + End Date + Due Date
- 注意,Vikunja这里并不只是把这几个attribute拿来排序/filter之类的。Vikunja居然支持甘特图!对于视觉类动物人类来说,有图,才清楚嘛。
- 至于 color, assignee, repeating。这类都是常规操作了。
Vikunja还有一些通常只在Project Management上面能看到的高级功能,比如Gantt Chart and Kanban。有时候家庭事项也是需要正经的时间管理的,支持甘特图和看板大大提高了这个TODO工具的适用范围。
Vikunja同时也支持CalDAV。虽然个人对这个协议目前不是很感冒,因为各家server对它的支持都比较参差不齐,有时候移动端桌面端使用这个协议的App,其feature set和CalDAV并不是很吻合,这个时候使用体验就相当凑合。不是不能用,但是不是这里打个折扣,就是那里缺个Feature,说不定哪天什么东西又不能用了。
Vikunja的不足
最大的不足就是缺乏移动端的支持。现在是通过PWA来做移动端,其实就相当于网页。虽然作为PWA来说,体验也很不错了,移动端的UX优化也是可以的了。但是因为是网页,所以不可能有离线支持。这对于移动端来讲就有点可惜。如果坐飞机的时候想事情,分析某个项目的Action Items List的话,没法访问服务器,就没法记录,实在是有点可惜(只是举个例子)。
不过Vikunja似乎在复活移动端的App
下载了试用了一下,似乎还是不太能用。希望以后可以越来越好吧。
顺便吐槽一下iOS的政策。每年那么贵的developer fee。对于开源生态的开发者开发iOS的APP实在不友好。不过想一下,iOS似乎也没有什么理由针对开源开发者免费,有钱不赚WBD嘛。因此很可能就算以后有了iOS的native application,估计也很难是免费的了。
Docker部署
官方给了比较详尽的文档,有Walkthrough还有一些范例:
在这里说一下几个需要注意的地方:
- 刨除DB,这个架构里面有两个Endpoint,一个是API的,也就是主要的后端。还有一个叫Frontend,大概就是处理一些Frontend方面的请求。如果在这个Docker Stack里面,我们不用一个Proxy把这两者都合并在一个port上面的话,如果我们还缺少一个自己的Reverse Proxy,那么我们就需要Expose两个Port出去,而且这两个Port都需要绑定Public Domain上面。这个就比较蛋疼了。Frontend肯定可以绑80端口,但是API呢?如果API给个7777端口,那么你就需要在你家的Port Forwarding上面再开个7777端口。这自然是完全不合理的。
- 如果我们自己有一个Reverse Proxy,那么如果只运行这两个Container,是可以的,只需要把directory到port的这一步mapping在你自己的Reverse Proxy上面搞定就可以了。这里官方还专门针对Nginx Proxy Manager给了一个教程。但是我还是嫌麻烦,不想在Nginx Proxy Manager上面搞太多特殊设置,因为这些设置不在我自己的Version Control下面管理。
- 所以最终一个比较好的方案,还是在我们的Stack里面添加一个Proxy,然后在NPM上面在代理这个Proxy,并作SSL卸载,就可以了。
- Vikunja默认是开启了注册的。在Docker compose API service里面,给定 “VIKUNJA_SERVICE_ENABLEREGISTRATION: false” 才能让注册关闭。不过需要注意,VIKUNJA似乎不太有管理员用户的概念,所以第一个用户还是要通过自己注册上去的。后面如果要添加用户,也是需要打开注册的。似乎并没有别的App里面常用的,邀请,或者由管理员添加用户,这样的方式。
最终我的Docker compose YAML 设这样的
version: '3'
services:
api:
image: vikunja/api:0.21
environment:
VIKUNJA_DATABASE_HOST: db
VIKUNJA_DATABASE_PASSWORD: secret
VIKUNJA_DATABASE_USER: vikunja
VIKUNJA_DATABASE_DATABASE: vikunja
VIKUNJA_SERVICE_JWTSECRET: <redacted>
# Timezone string here is case sensitive!
VIKUNJA_SERVICE_TIMEZONE: America/Los_Angeles
TZ: America/Los_Angeles
# Set this to ture in your first deployment
VIKUNJA_SERVICE_ENABLEREGISTRATION: false
VIKUNJA_SERVICE_FRONTENDURL: http://vikunja.example.com/
# Use a specific path for content of SQLite
# For single user/family uses, SQLite should be more than enough
VIKUNJA_DATABASE_PATH: /db/vikunja.db
VIKUNJA_DATABASE_TYPE: sqlite
ports:
- 3456:3456
volumes:
- /mnt/app_data/vikunja/files:/app/vikunja/files
# Using the custom DB path.
# You may need to manually check the owner/group of the directory.
# Vikunja by default runs in 1000:1000, but the folder is probably created with 0:0 (i.e. root:root).
- /mnt/app_data/vikunja/db:/db
restart: unless-stopped
frontend:
image: vikunja/frontend:0.21
restart: unless-stopped
# By using the proxy here, we don't need to maintain the director->port mapping the Nginx Proxy Manager.
# The NPM side can be configured just like a normal webapp.
proxy:
image: nginx
ports:
- 8060:80
volumes:
# Copy the nginx.conf in this code base to the corresponding location.
# Portainer does not check out the nginx.conf file to the docker compose directory
# (at least this is what I observed in my experiment)
- /mnt/app_data/vikunja/nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- api
- frontend
restart: unless-stopped
另外还需要的就是nginx.conf
。这里用官方文档提供的即可,然后放在/mnt/app_data/vikunja/nginx.conf
这里。如果觉得上传的限额太小了,改就好了,比如下面的改成5GB。大概在TODO里面不会有大于5GB的附件了吧。
nginx.conf:
server {
listen 80;
location / {
proxy_pass http://frontend:80;
}
location ~* ^/(api|dav|\.well-known)/ {
proxy_pass http://api:3456;
client_max_body_size 5000M;
}
}
可以看到,我这里所有的persistent volume都是映射到了/mnt/app_data/下面。这个文件夹是个 NFS mount。相当于给之后如果要把applications迁移到Kubernetes上面,做一些准备。还是那句话,binary和data要尽量解耦,至少要有那么个意思。
比较可惜的就是nginx.conf在这里我没有放在Gitea上面,而是当作application data处理了。实际上config也应该在version control(或者由version control驱动的data pusher里面,比如Google里面的CDPush)里面。不过个人玩具嘛,不要太认真。实际上是因为 Portainer CE里面,如果用 repository来部署stack的话,似乎并不会把跟 docker-compose.yml同一个目录下的nginx.conf也放到Portainer CE放Stack YAML的地方。这点跟之前在 .env 文件上看到的不一样。不知道是不是Portainer CE对于.env有什么不同的处理方法。对于使用Portainer EE的小伙伴,Enable Relative Path Volumes应该可以做到。
NOTE
💡 后来查看 Portainer存放 docker-compose的地方,发现实际上nginx.conf 是被 clone 出来了。但是UID:GID都是root:root。这个permission的问题可能才是为什么 nginx.conf 并无法正常使用的原因。
Docker container(s)搞定之后,只需要把Proxy上面expose的8060端口放出去就可以了。基本就是:
- OPNSense 的UnboundDNS(总之就是你家内网的DNS)上面创建新的Override,给到这个 vikunja.example.com,自然也是导到reverse proxy上面。我这里就是Nginx Proxy Manager (NPM)。这个实际是给内网用的。不加也成,就是要去公网DNS上面绕一圈。
- 公网DNS上面添加新的subdomain。自家路由器上面应该已经搞定了Port Forward才对。
- Nginx Proxy Manager上面创建新的Host Proxy,申请新的SSL证书。申请SSL证书这一步要求公网DNS和port forwarding没有问题了。
之后登录vikunja.example.com就可以了。
Nextcloud Task/Deck的问题
- 分Task和Deck → 简单的事情变复杂了
对于个人用户来讲,使用的时候还需要区分我用的是什么工具。这本身就复杂了。TODO工具一个重要的功能就是降低用户在开始要干活的时候的心理障碍,就是需要尽可能的无脑,无感。所以任何时候多加一个用户需要回答的问题,如果不是绝对必要的,都应该尽量避免。
-
NC is buggy Deck还是有Bug。Tag的使用一直有点不太稳定。Task似乎还可以,但是感觉上Task的功能还是不够全面。有的时候,虽然是个人用户,但是也需要一些功能,来处理一些相对来讲复杂的事情。比如搬家,比如大额支出,大的房屋修葺方面的“工程”。这个时候实际上Deck更合适。但是又回到第一个问题,为啥要分两个工具呢?
-
NC的历史包袱沉重 NC,一个基于PHP的,致力于一次性解决所有问题的,Super App。实际上是很难兼顾各个方面的。对于企业用户来讲,因为需要统一管理,还需要各种工具集成(无论这些工具放一起多么不好用,不重要,先有个方案能凑合再说),NC是一个合理的选择。而且企业用户实际上是有专人负责IT的,所以,有些维护成本高的问题,实际上不太是问题。但是对于个人用户来讲就不一定合适。
-
NC是All-in-one 这个特点其实就是仁者见仁智者见智了。跟上面的一样。All-in-one的方案,如果运行良好,就很好用,类似Google的生态那样。但是,NC实际上比较“凑合”,而个人用户自己一般都是各种折腾,很容易东西就挂了,一挂可能所有工具就都挂了。比如我要是为了折腾一个NC上面好用的Photo Gallery,我一不小心把NC搞挂了,那么我的TODO也就没有了,File Browser也就没有了。这可能导致很严重的问题。
-
Limited Feature Set 如果我没记错的话,连repeating task这种都不支持。Task下面的subtask应该也没有无限嵌套。Deck里面的Project也没有无限嵌套。这些都大大限制了NC做Project Management + Personal TODO的使用场景。