feat: add koon money

This commit is contained in:
2025-10-20 17:43:36 -04:00
parent ab831218c9
commit 53142c9e02
4 changed files with 217 additions and 1 deletions

View File

@@ -16,6 +16,7 @@
./service/wakapi.nix ./service/wakapi.nix
./service/elytra.nix ./service/elytra.nix
./service/money.nix
]; ];
# Use the systemd-boot EFI boot loader. # Use the systemd-boot EFI boot loader.
@@ -52,6 +53,11 @@
"waka.koon.us" = "http://localhost:3006"; "waka.koon.us" = "http://localhost:3006";
"ride.koon.us" = "http://localhost:3007"; "ride.koon.us" = "http://localhost:3007";
"ride-api.koon.us" = "http://localhost:8080"; "ride-api.koon.us" = "http://localhost:8080";
"money.koon.us" = "http://localhost:3160";
"zero.koon.us" = "http://localhost:4848";
"money-api.koon.us" = "http://localhost:3161";
}; };
default = "http_status:404"; default = "http_status:404";
}; };

198
host/ark/service/money.nix Normal file
View File

@@ -0,0 +1,198 @@
{ pkgs, config, ... }:
let
src = pkgs.fetchgit {
url = "https://git.koon.us/max/money.git";
hash = "sha256-HG7R/rv6H7jIBp0qK3azy1x1myjOBJCQqI+K0ydztKs=";
};
expoWeb = pkgs.stdenv.mkDerivation (finalAttrs: {
pname = "expo-web";
version = "1.0.0";
src = src;
pnpm = pkgs.pnpm_10;
nativeBuildInputs = [
pkgs.nodejs
finalAttrs.pnpm.configHook
];
pnpmDeps = finalAttrs.pnpm.fetchDeps {
inherit (finalAttrs) pname version src;
fetcherVersion = 2;
hash = "sha256-x2zCFeMU0VfkVRILrLReEOFNrcd7aJp57v4fMGBE2dI=";
};
pnpmInstallFlags = [ "--frozen-lockfile" ];
buildPhase = ''
runHook preBuild
pnpm run build
runHook postBuild
'';
installPhase = ''
mkdir -p $out
cp -r dist/* $out/
'';
});
api = pkgs.stdenv.mkDerivation (finalAttrs: {
pname = "koon-money-api";
version = "1.0.1";
src = src;
pnpm = pkgs.pnpm_10;
nativeBuildInputs = [
pkgs.nodejs
finalAttrs.pnpm.configHook
pkgs.python3 # Required for node-gyp
pkgs.nodePackages.node-gyp # For building native modules
pkgs.pkg-config
pkgs.gnumake
pkgs.gcc
];
buildInputs = [
pkgs.sqlite
pkgs.sqlite.dev
pkgs.readline
pkgs.ncurses
pkgs.libbsd
];
pnpmDeps = finalAttrs.pnpm.fetchDeps {
inherit (finalAttrs) pname version src;
fetcherVersion = 2;
hash = "sha256-x2zCFeMU0VfkVRILrLReEOFNrcd7aJp57v4fMGBE2dI=";
};
NIX_CFLAGS_COMPILE = "-D_GNU_SOURCE";
pnpmInstallFlags = [ "--frozen-lockfile" ];
buildPhase = ''
runHook preBuild
cd node_modules/@rocicorp/zero-sqlite3
node-gyp rebuild --build-from-source
cd -
runHook postBuild
'';
installPhase = ''
mkdir -p $out
cp -r . $out/
'';
});
api-port = "3161";
in
{
services.nginx = {
enable = true;
virtualHosts."money.koon.us" = {
root = "${expoWeb}";
listen = [
{ addr = "127.0.0.1"; port = 3160; }
];
locations."/" = {
tryFiles = "$uri /index.html";
};
};
};
virtualisation.oci-containers = {
backend = "podman";
containers = {
zero = {
image = "rocicorp/zero:0.23.2025101600";
ports = ["127.0.0.1:4848:4848"];
volumes = [ "/run/postgresql:/run/postgresql" ];
environment = {
ZERO_UPSTREAM_DB = "postgresql://postgres@127.0.0.1/money";
ZERO_REPLICA_FILE = "/tmp/zync-replica.db";
ZERO_GET_QUERIES_URL = "http://localhost:${api-port}/api/zero/get-queries";
ZERO_GET_QUERIES_FORWARD_COOKIES = "true";
ZERO_MUTATE_URL = "http://localhost:${api-port}/api/zero/mutate";
ZERO_MUTATE_FORWARD_COOKIES = "true";
};
extraOptions = [ "--network=host" ];
};
};
};
services.postgresql = {
enable = true;
ensureDatabases = [ "money" ];
ensureUsers = [
{
name = "money";
ensureDBOwnership = true;
}
];
authentication = ''
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
'';
settings = {
wal_level = "logical";
};
};
systemd.services.money-api = {
description = "Money API";
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment = {
ZERO_UPSTREAM_DB = "postgresql://postgres@127.0.0.1/money";
PORT = api-port;
NODE_ENV = "production";
BETTER_AUTH_SECRET = "burger";
DEBUG = "*";
NODE_OPTIONS = "--trace-warnings --trace-uncaught";
OAUTH_DISCOVERY_URL = "https://auth.koon.us/.well-known/openid-configuration";
};
serviceConfig = {
Type = "simple";
User = "money";
Group = "money";
WorkingDirectory = "${api}/shared";
ExecStartPre = "${api}/node_modules/.bin/drizzle-kit push --config=${api}/shared/drizzle.config.ts";
ExecStart = pkgs.writeShellScript "money-api-start" ''
set -euo pipefail
export OAUTH_CLIENT_ID="$(cat ${config.sops.secrets."money/clientId".path})"
export OAUTH_CLIENT_SECRET="$(cat ${config.sops.secrets."money/clientSecret".path})"
exec ${api}/node_modules/.bin/tsx ${api}/api/src/index.ts
'';
EnvironmentFile = config.sops.secrets."money-env".path;
Restart = "on-failure";
RestartSec = 10;
SyslogIdentifier = "money-api";
StandardOutput = "journal";
StandardError = "journal";
};
};
users.users.money = {
isSystemUser = true;
home = "/var/lib/money";
createHome = true;
group = "money";
};
users.groups.money = {};
}

View File

@@ -31,6 +31,10 @@
owner = config.users.users.elytra-web.name; owner = config.users.users.elytra-web.name;
}; };
"money-env" = {
owner = config.users.users.money.name;
};
"photos/clientId" = { "photos/clientId" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml; sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
}; };
@@ -55,6 +59,14 @@
sopsFile = ../../secrets/sops/host/ark/oauth.yaml; sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
owner = config.services.outline.user; owner = config.services.outline.user;
}; };
"money/clientId" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
owner = config.users.users.money.name;
};
"money/clientSecret" = {
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
owner = config.users.users.money.name;
};
}; };
}; };
} }

Submodule secrets updated: e13ba457d4...fdda3b7b10