infrastructure

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit e1a589dbd2fe987374c4b1330c3656a38ebc7cb5
parent 47fdc6b188dbbc055c2dba7b9ea055458db9e85b
Author: Silas Brack <silasbrack@gmail.com>
Date:   Sun, 31 May 2026 22:22:22 +0200

feat: implement daily tracker

Diffstat:
Mflake.lock | 83++++++++++++++-----------------------------------------------------------------
Mflake.nix | 9++++++---
Mhosts/helios.nix | 17++++++++++-------
Amodules/daily-tracker.nix | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msecrets.yaml | 6++++--
5 files changed, 152 insertions(+), 81 deletions(-)

diff --git a/flake.lock b/flake.lock @@ -16,19 +16,21 @@ "type": "gitlab" } }, - "crane": { + "daily-tracker": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, "locked": { - "lastModified": 1776635034, - "narHash": "sha256-OEOJrT3ZfwbChzODfIH4GzlNTtOFuZFWPtW7jIeR8xU=", - "owner": "ipetkov", - "repo": "crane", - "rev": "dc7496d8ea6e526b1254b55d09b966e94673750f", - "type": "github" + "lastModified": 1780258828, + "narHash": "sha256-U7sAzfC2K1Ac/X+wm2pKZp83ENBt+iKTPwq8M5yczeE=", + "path": "/home/silas/dev/elixir-web-app/daily_tracker", + "type": "path" }, "original": { - "owner": "ipetkov", - "repo": "crane", - "type": "github" + "path": "/home/silas/dev/elixir-web-app/daily_tracker", + "type": "path" } }, "flake-compat": { @@ -227,22 +229,6 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1776548001, - "narHash": "sha256-ZSK0NL4a1BwVbbTBoSnWgbJy9HeZFXLYQizjb2DPF24=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "b12141ef619e0a9c1c84dc8c684040326f27cdcc", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_4": { - "locked": { "lastModified": 1775888245, "narHash": "sha256-nwASzrRDD1JBEu/o8ekKYEXm/oJW6EMCzCRdrwcLe90=", "owner": "NixOS", @@ -259,60 +245,19 @@ }, "root": { "inputs": { + "daily-tracker": "daily-tracker", "home-manager": "home-manager", "mkv": "mkv", "nixos-mailserver": "nixos-mailserver", "nixpkgs": "nixpkgs_2", "nixpkgs-unstable": "nixpkgs-unstable", - "simple-web-app": "simple-web-app", "sops-nix": "sops-nix", "website": "website" } }, - "rust-overlay": { - "inputs": { - "nixpkgs": [ - "simple-web-app", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1776654897, - "narHash": "sha256-Vqi4AiJVCcBGn/RmBtRCgyH5rCxqm/w0xV9diJWF1Ic=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "25d75be8139815a53560745fa060909777495105", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - }, - "simple-web-app": { - "inputs": { - "crane": "crane", - "nixpkgs": "nixpkgs_3", - "rust-overlay": "rust-overlay" - }, - "locked": { - "lastModified": 1777147695, - "narHash": "sha256-qYkrQPehfGzoWHMlVC9IG3U7xWOXUl93v6/KrEnjHJY=", - "ref": "refs/heads/main", - "rev": "ae4c3f76eef6a15a54860d6283eec80960e22651", - "revCount": 63, - "type": "git", - "url": "ssh://forgejo@git.fnarglebeast.com/silas/simple-web-app.git" - }, - "original": { - "type": "git", - "url": "ssh://forgejo@git.fnarglebeast.com/silas/simple-web-app.git" - } - }, "sops-nix": { "inputs": { - "nixpkgs": "nixpkgs_4" + "nixpkgs": "nixpkgs_3" }, "locked": { "lastModified": 1777338324, diff --git a/flake.nix b/flake.nix @@ -3,7 +3,10 @@ nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; sops-nix.url = "github:Mic92/sops-nix"; - simple-web-app.url = "git+ssh://forgejo@git.fnarglebeast.com/silas/simple-web-app.git"; + daily-tracker = { + url = "path:/home/silas/dev/elixir-web-app/daily_tracker"; + inputs.nixpkgs.follows = "nixpkgs"; + }; mkv.url = "git+ssh://git@github.com/silasbrack/mkv"; website = { url = "git+ssh://forgejo@git.fnarglebeast.com/silas/website.git"; @@ -23,7 +26,7 @@ nixpkgs, nixpkgs-unstable, sops-nix, - simple-web-app, + daily-tracker, mkv, website, nixos-mailserver, @@ -53,7 +56,7 @@ pkgs, ... }: - import ./hosts/helios.nix (inputs // { inherit simple-web-app mkv website; }) + import ./hosts/helios.nix (inputs // { inherit daily-tracker mkv website; }) ) ]; }; diff --git a/hosts/helios.nix b/hosts/helios.nix @@ -2,7 +2,7 @@ pkgs, config, lib, - simple-web-app, + daily-tracker, mkv, website, ... @@ -14,7 +14,7 @@ ../modules/mediawiki.nix ../modules/forgejo.nix ../modules/mkv.nix - ../modules/simple-web-app.nix + ../modules/daily-tracker.nix ../modules/mailserver.nix ]; @@ -116,13 +116,16 @@ }; }; - # Simple Web App - services.simple-web-app = { + # Daily Tracker + services.local.daily-tracker = { enable = true; - package = simple-web-app.packages.${pkgs.stdenv.hostPlatform.system}.default; - trailbasePackage = simple-web-app.packages.${pkgs.stdenv.hostPlatform.system}.trailbase; - traildepotPath = "${simple-web-app}/traildepot"; + package = daily-tracker.packages.${pkgs.stdenv.hostPlatform.system}.default; + domain = "simple.fnarglebeast.com"; + secretKeyBaseSecretName = "daily_tracker_secret_key_base"; + mailPasswordSecretName = "daily_tracker_mail_password"; }; + sops.secrets.daily_tracker_secret_key_base = { }; + sops.secrets.daily_tracker_mail_password = { }; # Mail server services.local.mailserver = { diff --git a/modules/daily-tracker.nix b/modules/daily-tracker.nix @@ -0,0 +1,118 @@ +{ + config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.local.daily-tracker; +in +{ + options.services.local.daily-tracker = { + enable = lib.mkEnableOption "Daily Tracker"; + + package = lib.mkOption { + type = lib.types.package; + description = "The daily_tracker release package"; + }; + + domain = lib.mkOption { + type = lib.types.str; + description = "Domain for the daily tracker"; + }; + + port = lib.mkOption { + type = lib.types.int; + default = 4000; + description = "Port for the Phoenix server"; + }; + + secretKeyBaseSecretName = lib.mkOption { + type = lib.types.str; + description = "Sops secret name for SECRET_KEY_BASE"; + }; + + mailPasswordSecretName = lib.mkOption { + type = lib.types.str; + description = "Sops secret name for MAIL_PASSWORD"; + }; + + databaseName = lib.mkOption { + type = lib.types.str; + default = "daily_tracker"; + description = "PostgreSQL database name"; + }; + }; + + config = lib.mkIf cfg.enable { + services.postgresql = { + enable = true; + ensureDatabases = [ cfg.databaseName ]; + ensureUsers = [ + { + name = "daily_tracker"; + ensureDBOwnership = true; + } + ]; + authentication = '' + local ${cfg.databaseName} daily_tracker trust + host ${cfg.databaseName} daily_tracker 127.0.0.1/32 trust + ''; + }; + + systemd.services.daily-tracker = { + wantedBy = [ "multi-user.target" ]; + description = "Daily Tracker Phoenix app"; + after = [ "network.target" "postgresql.service" ]; + requires = [ "postgresql.service" ]; + serviceConfig = { + Type = "exec"; + ExecStartPre = "${cfg.package}/bin/daily_tracker eval 'DailyTracker.Release.migrate()'"; + ExecStart = "${cfg.package}/bin/daily_tracker start"; + Restart = "on-failure"; + User = "daily_tracker"; + Group = "daily_tracker"; + StateDirectory = "daily-tracker"; + WorkingDirectory = "/var/lib/daily-tracker"; + }; + environment = { + PHX_SERVER = "true"; + PHX_HOST = cfg.domain; + PORT = builtins.toString cfg.port; + DATABASE_URL = "ecto://daily_tracker@127.0.0.1/${cfg.databaseName}"; + MAIL_HOST = "localhost"; + RELEASE_COOKIE = "daily-tracker-cookie"; + }; + }; + + # Load secrets into the service environment + systemd.services.daily-tracker.serviceConfig.EnvironmentFile = [ + config.sops.templates."daily-tracker-env".path + ]; + + sops.templates."daily-tracker-env" = { + content = '' + SECRET_KEY_BASE=${config.sops.placeholder.${cfg.secretKeyBaseSecretName}} + MAIL_PASSWORD=${config.sops.placeholder.${cfg.mailPasswordSecretName}} + ''; + owner = "daily_tracker"; + }; + + users.users.daily_tracker = { + isSystemUser = true; + group = "daily_tracker"; + }; + users.groups.daily_tracker = { }; + + services.nginx.virtualHosts.${cfg.domain} = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://127.0.0.1:${builtins.toString cfg.port}"; + recommendedProxySettings = true; + proxyWebsockets = true; + }; + }; + }; +} diff --git a/secrets.yaml b/secrets.yaml @@ -8,6 +8,8 @@ gaia_forgejo_runner_token: ENC[AES256_GCM,data:0XA6nSeBW4uh/cx/95xw0Ood/a68qD4Z/ gaia_gitea_runner_ssh_key: ENC[AES256_GCM,data:CZZMptDd9s7WQsx9vnHv7tF1CJ9cKd+lnwuv75+a1p4OWxANObfIFtJOTDDHNL1+fk4/48/OOtODrgZlfeLxVPmmiPsvnSPOA1POhi6q97bpOWk/YWgViIWaf4UsLWDBq3/tngcJCa5JebrKuY+T7MaJn1Lw+C8h+91WiIWYSzOSMmZIoMDo5Y85cPqesFKxgmSlgTYbv5mJnFQ6pvhqTLHRpIPW5PNgRjeXsjJrblvs/edYtLyAVm6H0IYMiMa24+272f90l/2Vc16PXk6RCCFIIJ9HuGYGRBFMAD0bYPDo/ESTMn2u1MATGVCPKCLMjTxFglowfavZpb7xLk7EvZoWPQXx/+KcTV3+iVabOv0kI8OLZFGUPCs4B1MiIeCfSLEr4nop2SNm3C7pGFuKJ0EFGbnhdfBqBqVKZVkXJNGY023BHC3eXx57VatisHQAwLbs2qgSWvOetTAhw8E12QylFtq6mXWG3lZuhJxoiZ6QMI9Yjc/Fvxt4NBOjFtbF0iDRd0g0FSv+geQ7BNid,iv:ufcXcVm2NQRTmG7mYDPwCihm4SYkQ9llpoKtP73Z9Ik=,tag:g4RNNXCBZL0EluwGTYC7fA==,type:str] gaia_forgejo_access_token: ENC[AES256_GCM,data:KpAnvpevOWgbNrEr+QynldkDqonVD90MuVDrBwG7mBClZxHfcps6aw==,iv:22zJ3/BBu5/aFMjgwhQ3lJH+lzOT53bozdAdrzMUGRI=,tag:Vic8ZfT43b0CfphZ/hP1DQ==,type:str] mail_silas_password_hash: ENC[AES256_GCM,data:E3NCQ5/eRfpbaOVpK0Ovk/vE+h1q5/z7rZrSelQy2Qc++a6nMYA/q7/YmfFT2R68JwOJMaeNMnOKjn1A,iv:sGgRC5SRRiziBd5TVO273uouyFhRqvB0e04xDhifSfM=,tag:U1QxtlVbDUw+nhFm+ZnxOA==,type:str] +daily_tracker_secret_key_base: ENC[AES256_GCM,data:kLjV/cxP/s8DJ+hAwGdKmzU+hQohEU1/tjBIrONtHQT/baYn874rHf1KYgn05OXP7J9074favlH4h1aQco+6og==,iv:7nSTefY8B19hGCW0XK/perQoRhgHxLD3dAcMrDbPlgw=,tag:HCAoGDcKE92ms4SpwEl3AA==,type:str] +daily_tracker_mail_password: ENC[AES256_GCM,data:XCaEsrOmLoCQFurRc5X8l2YrtwGlp61j97XQTtPNGndzjqwXsjHfdHb/QO+V978fw9ZOWNrYKuSPR/t1,iv:jjhjPkyWmMFgPYQqNFagEttTW1b0u8nwSWiwKR+xT2U=,tag:WzCqt2S26vqO2I6sH3qqYQ==,type:str] sops: age: - recipient: age1s29qgfupgx7mqn9dk2rndp6xh63f5qan8vqa77ve603wd5m9a9rqkpq7re @@ -46,7 +48,7 @@ sops: ZGptR25vdWhEKzFxbE5qS051ZFF4RkEK1hGCQVE1E92nFSwSeYRRhxn2p3wBfhpS TZMRsiXtUdlgnoa+IJcFKsbwaZspYnKCA93IEfOXy6TadcoNiFzypw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-31T11:49:47Z" - mac: ENC[AES256_GCM,data:6X9/faApExW9xtorxSAODyVQwSCtDTel0iTtc7ZaeRgiRqQmpPTw8bZ4Zln51lWqUO3EOSRH6ge2btNrtQbPmZoBAmh0dntDvB6LsvJn3NVDeq5vM3vV1dMDyjiXBMqxT99tYkTSK08j10QcCLRRkHIoj4wHIabg7INPCpNadnA=,iv:18yZmCDZzRf96i7L72ogvwCJ6rHvGhzvA0Pq07Jhy08=,tag:j8xTjdG7tndylumNkNVFGA==,type:str] + lastmodified: "2026-05-31T20:15:47Z" + mac: ENC[AES256_GCM,data:bEFC9WYUYvXlbBfUe9+biAUc4QkSkIS0DO6qtIwDCOu32PmNHC6NDjE/ZzWCgwx6QOm0BH/5JKIEdiH1XhegOKi2BmH1M6tqRE3U7sHh2DCCn+bf9PuoKW/dcjXAQp7QS9MLZkTgw0HepKixiL6WAaszYNs9DtOhZzFEjHs8WSs=,iv:Sh8mCK4VbLSnf+eOYeI2YBjfDQIfQYc2XJGgw63I4kE=,tag:5hUMPrVbhCdIZr8VuvsrOA==,type:str] unencrypted_suffix: _unencrypted version: 3.12.1