{
  inputs.haskell-nix.url = "github:input-output-hk/haskell.nix";
  inputs.nixpkgs.follows = "haskell-nix/nixpkgs-unstable";
  inputs.flake-utils.follows = "haskell-nix/flake-utils";

  inputs.docker-nixpkgs = {
    url = "github:nix-community/docker-nixpkgs";
    flake = false;
  };

  inputs.encoding = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/encoding.git?ref=uni2work";
    flake = false;
  };
  inputs.memcached-binary = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/memcached-binary.git?ref=uni2work";
    flake = false;
  };
  inputs.conduit-resumablesink = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/conduit-resumablesink.git?ref=uni2work";
    flake = false;
  };
  inputs.HaskellNet-SSL = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/HaskellNet-SSL.git?ref=uni2work";
    flake = false;
  };
  inputs.ldap-client = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/ldap-client.git?ref=uni2work";
    flake = false;
  };
  inputs.serversession = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/serversession.git?ref=uni2work";
    flake = false;
  };
  inputs.xss-sanitize = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/xss-sanitize.git?ref=uni2work";
    flake = false;
  };
  inputs.colonnade = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/colonnade.git?ref=uni2work";
    flake = false;
  };
  inputs.minio-hs = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/minio-hs.git?ref=uni2work";
    flake = false;
  };
  inputs.cryptoids = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/cryptoids.git?ref=uni2work";
    flake = false;
  };
  inputs.zip-stream = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/zip-stream.git?ref=uni2work";
    flake = false;
  };
  inputs.yesod = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/yesod.git?ref=uni2work";
    flake = false;
  };
  inputs.cryptonite = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/cryptonite.git?ref=uni2work";
    flake = false;
  };
  inputs.esqueleto = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/esqueleto.git?ref=uni2work";
    flake = false;
  };

  inputs.tail-DateTime = {
    url = "git+ssh://git@gitlab2.rz.ifi.lmu.de/uni2work/tail.DateTime.git?ref=uni2work";
    flake = false;
  };
  inputs.fontawesome-token = {
    url = "path:/etc/fontawesome-token";
    flake = false;
  };

  outputs = inputs@{ self, nixpkgs, flake-utils, haskell-nix, docker-nixpkgs, ... }: flake-utils.lib.eachSystem ["x86_64-linux"]
    (system:
      let frontendSource = pkgs.lib.sourceByRegex ./. [
            "^(assets|frontend)(/.*)?$"
            "^config(/(favicon\.json|robots\.txt))?$"
            "^(webpack|postcss)\.config\.js$"
            "^karma\.conf\.js$"
            "^(package|jsconfig|\.eslintrc)\.json$"
            "^\.babelrc$"
          ];
          backendSource = pkgs.lib.sourceByRegex ./. [
            "^(\.hlint|package|stack-flake)\.yaml$"
            "^stack\.yaml\.lock$"
            "^(assets|app|hlint|load|messages|models|src|templates|test|testdata)(/.*)?$"
            "^config(/(archive-types|mimetypes|personalised-sheet-files-collate|settings\.yml|submission-blacklist|test-settings\.yml|video-types|wordlist\.txt))?$"
            "^routes$"
            "^testdata(/.*)?$"
          ];

          pkgs = import nixpkgs {
            inherit system overlays;
            config.allowUnfree = true;
          };
          overlays = [
            # remove once https://github.com/NixOS/nix/pull/5266 has landed in nixpkgs used here (see flake.lock)
            (import ./nix/aws-patch.nix)
            # end remove

            (import "${docker-nixpkgs}/overlay.nix")

            (import ./nix/maildev)
            haskell-nix.overlay
            (import ./nix/uniworx { inherit inputs frontendSource backendSource; })
            (import ./nix/docker { inherit self; })
            (import ./nix/parse-changelog.nix {})
          ];
          haskellFlake = pkgs.uniworx.flake {};

          mkPushDocker = imageName: dockerImage: pkgs.writeScriptBin "push-${dockerImage.imageName}" ''
            #!${pkgs.zsh}/bin/zsh -xe

            target=''${1-docker://registry.gitlab.com/fradrive/fradrive/${imageName}:${dockerImage.imageTag}}
            [[ -n "''${1}" ]] && shift
            ${pkgs.skopeo}/bin/skopeo ''${@} --insecure-policy copy docker-archive://${dockerImage} ''${target}
          '';
      in {
        packages = haskellFlake.packages // {
          inherit (pkgs) uniworxNodeDependencies uniworxWellKnown uniworxFrontend uniworxDemoDocker uniworxDocker ciDocker changelogJson;
        };
        apps = haskellFlake.apps // {
          pushUniworxDemoDocker = flake-utils.lib.mkApp { drv = mkPushDocker "uniworx-demo" pkgs.uniworxDemoDocker; };
          pushUniworxDocker = flake-utils.lib.mkApp { drv = mkPushDocker "uniworx" pkgs.uniworxDocker; };
          pushCIDocker = flake-utils.lib.mkApp { drv = mkPushDocker "nix-unstable" pkgs.ciDocker; };
          calculateMaterializedSha = flake-utils.lib.mkApp { drv = pkgs.uniworx.stack-nix.passthru.calculateMaterializedSha; exePath = ""; };
          jqChangelogJson = flake-utils.lib.mkApp { drv = pkgs.jqChangelogJson; };
        };
        checks = haskellFlake.checks // {
          uniworxFrontend = pkgs.uniworxFrontend.check;
        };
        
        devShell = import ./shell.nix { inherit pkgs; };

        legacyPackages = pkgs;

        defaultPackage = self.packages.${system}."uniworx:exe:uniworx";
        defaultApp = self.apps.${system}."uniworx:exe:uniworx";
      }
    );
}
