{ lib, pkgs, config, ... }: let types = { jwtSettings = { session_time = lib.mkOption { type = lib.types.str; default = "168h"; }; max_refresh = lib.mkOption { type = lib.types.str; default = "168h"; }; }; serverSettings = { port = lib.mkOption { type = lib.types.int; default = 2021; }; read_timeout = lib.mkOption { type = lib.types.str; default = "10s"; }; write_timeout = lib.mkOption { type = lib.types.str; default = "10s"; }; rate_period = lib.mkOption { type = lib.types.str; default = "60s"; }; rate_limit = lib.mkOption { type = lib.types.int; default = 300; }; cors_allow_origins = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ "http://localhost:5173" "http://localhost:7926" "https://localhost" "capacitor://localhost" ]; }; serve_frontend = lib.mkOption { type = lib.types.bool; default = true; }; }; schedulerSettings = { due_job = lib.mkOption { type = lib.types.str; default = "30m"; }; overdue_job = lib.mkOption { type = lib.types.str; default = "3h"; }; pre_due_job = lib.mkOption { type = lib.types.str; default = "3h"; }; }; emailSettings = { host = lib.mkOption { type = lib.types.str; default = ""; }; port = lib.mkOption { type = lib.types.int; default = 587; }; email = lib.mkOption { type = lib.types.str; default = ""; }; key = lib.mkOption { type = lib.types.str; default = ""; }; }; oauth2Settings = { client_id = lib.mkOption { type = lib.types.str; default = ""; }; client_secret = lib.mkOption { type = lib.types.str; default = ""; }; auth_url = lib.mkOption { type = lib.types.str; default = ""; }; token_url = lib.mkOption { type = lib.types.str; default = ""; }; user_info_url = lib.mkOption { type = lib.types.str; default = ""; }; redirect_url = lib.mkOption { type = lib.types.str; default = ""; }; name = lib.mkOption { type = lib.types.str; default = ""; }; }; settings = lib.types.submodule { options = { is_user_creation_disabled = lib.mkEnableOption "Disable user creation"; telegram.token = lib.mkOption { type = lib.types.str; default = ""; }; pushover.token = lib.mkOption { type = lib.types.str; default = ""; }; jwt = types.jwtSettings; server = types.serverSettings; scheduler_jobs = types.schedulerSettings; email = types.emailSettings; oauth2 = types.oauth2Settings; }; }; }; version = "0.0.33"; package = pkgs.stdenv.mkDerivation { name = "donetick"; src = pkgs.fetchurl { url = "https://github.com/donetick/donetick/releases/download/v${version}/donetick_Linux_arm64.tar.gz"; hash = "sha256-o5PcONv+fxBMToOCwBcr2fnSpsHn5bdfujyUTuMKTbI="; }; nativeBuildInputs = [ pkgs.autoPatchelfHook ]; sourceRoot = "."; installPhase = '' runHook preInstall install -Dm755 donetick $out/bin/donetick runHook postInstall ''; meta = with pkgs.lib; { description = "A self-hosted task and chore manager"; license = licenses.mit; mainProgram = "donetick"; }; }; cfg = config.services.donetick; fqdn = "${cfg.subdomain}.${config.networking.domain}"; immutableSettings = { name = "selfhosted"; is_done_tick_dot_com = false; email.appHost = "https://${fqdn}"; database = { type = "sqlite"; migration = true; }; }; settings = (pkgs.formats.yaml { }).generate "selfhosted.yaml" (cfg.settings // immutableSettings); secrets = config.age.secrets; in { options.services.donetick = { enable = lib.mkEnableOption "Enable donetick"; subdomain = lib.mkOption { type = lib.types.str; }; settings = lib.mkOption { type = types.settings; }; }; config = lib.mkIf cfg.enable { systemd.services.donetick = { enable = true; environment = { DT_ENV = "selfhosted"; }; serviceConfig = { DynamicUser = true; ExecStart = "${package}/bin/donetick"; BindReadOnlyPaths = [ "${settings}:/var/lib/donetick/config/selfhosted.yaml" /run/systemd/resolve/stub-resolv.conf /etc/ssl /etc/static/ssl /etc/resolv.conf /etc/static/resolv.conf /etc/nsswitch.conf /etc/static/nsswitch.conf /etc/hosts ]; WorkingDirectory = "/var/lib/donetick"; StateDirectory = "donetick"; EnvironmentFile = secrets.donetick.path; }; wantedBy = [ "multi-user.target" ]; confinement.enable = true; }; services.webserver = { enable = lib.mkDefault true; vHosts.${fqdn}.locations."/" .proxyPort = cfg.settings.server.port; }; }; }