mirror of
https://github.com/thegeneralist01/config.git
synced 2026-05-30 08:37:01 +02:00
Compare commits
No commits in common. "6e1e8c1b8f6cec5d957c415bdc6bfabfd5801757" and "4f4995cf75166e1b7107b65983960dfeedf917e1" have entirely different histories.
6e1e8c1b8f
...
4f4995cf75
18 changed files with 395 additions and 137 deletions
105
flake.lock
generated
105
flake.lock
generated
|
|
@ -44,6 +44,25 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"calorie-tracker": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1771309191,
|
||||||
|
"narHash": "sha256-Y83E1JrimzUPQ1a7FpOd9dIQFJFucbV4lYPI7ik3Piw=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "8cf458087edb5f2ff7e3563d4bb6e489c3264d1d",
|
||||||
|
"revCount": 2,
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/thegeneralist/calorie-tracker"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/thegeneralist/calorie-tracker"
|
||||||
|
}
|
||||||
|
},
|
||||||
"fenix": {
|
"fenix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
|
@ -81,22 +100,6 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-compat_2": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1747046372,
|
|
||||||
"narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_2"
|
"systems": "systems_2"
|
||||||
|
|
@ -154,7 +157,7 @@
|
||||||
"ghostty": {
|
"ghostty": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils_2",
|
||||||
"nixpkgs-stable": "nixpkgs-stable",
|
"nixpkgs-stable": "nixpkgs-stable",
|
||||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
"zig": "zig",
|
"zig": "zig",
|
||||||
|
|
@ -174,28 +177,6 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"helium": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat_2",
|
|
||||||
"flake-utils": "flake-utils_2",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1772006043,
|
|
||||||
"narHash": "sha256-TZfnQqC2kvP6eDlDrKjbClijnpCPEcoCiopdy3M3ib4=",
|
|
||||||
"owner": "AlvaroParker",
|
|
||||||
"repo": "helium-nix",
|
|
||||||
"rev": "2bcf84a8e83984e3b7054d29d8890d7ae903c91f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "AlvaroParker",
|
|
||||||
"repo": "helium-nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
|
@ -289,11 +270,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1755186698,
|
"lastModified": 1771008912,
|
||||||
"narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=",
|
"narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c",
|
"rev": "a82ccc39b39b621151d6732718e3e250109076fa",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
@ -336,6 +317,22 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1755186698,
|
||||||
|
"narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1769789167,
|
"lastModified": 1769789167,
|
||||||
"narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=",
|
"narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=",
|
||||||
|
|
@ -354,34 +351,34 @@
|
||||||
"readlater-bot": {
|
"readlater-bot": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_3",
|
"flake-utils": "flake-utils_3",
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1772524468,
|
"lastModified": 1771250778,
|
||||||
"narHash": "sha256-h/NmNoiBVPzxm/yDhl+Z8PaFJeDtPz8Ef7NQeZgn8TE=",
|
"narHash": "sha256-lmWwzbuMer8vjGXh37p79dSctaFNjTBW6Cp0T5R+ZiE=",
|
||||||
"owner": "thegeneralist01",
|
"ref": "refs/heads/master",
|
||||||
"repo": "bookkeeper",
|
"rev": "181c03915b93d21c5d15a1375d3bc621b2992700",
|
||||||
"rev": "e1afcc51485ed9b80211a2c48a3e93ef4d6b35f5",
|
"revCount": 17,
|
||||||
"type": "github"
|
"type": "git",
|
||||||
|
"url": "file:///home/thegeneralist/infofeeder-bot"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "thegeneralist01",
|
"type": "git",
|
||||||
"repo": "bookkeeper",
|
"url": "file:///home/thegeneralist/infofeeder-bot"
|
||||||
"type": "github"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"agenix": "agenix",
|
"agenix": "agenix",
|
||||||
|
"calorie-tracker": "calorie-tracker",
|
||||||
"fenix": "fenix",
|
"fenix": "fenix",
|
||||||
"ghostty": "ghostty",
|
"ghostty": "ghostty",
|
||||||
"helium": "helium",
|
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"homebrew-cask": "homebrew-cask",
|
"homebrew-cask": "homebrew-cask",
|
||||||
"homebrew-core": "homebrew-core",
|
"homebrew-core": "homebrew-core",
|
||||||
"nix-darwin": "nix-darwin",
|
"nix-darwin": "nix-darwin",
|
||||||
"nix-homebrew": "nix-homebrew",
|
"nix-homebrew": "nix-homebrew",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"readlater-bot": "readlater-bot"
|
"readlater-bot": "readlater-bot"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
10
flake.nix
10
flake.nix
|
|
@ -42,14 +42,12 @@
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
helium = {
|
readlater-bot = {
|
||||||
# url = "github:FKouhai/helium2nix/main";
|
url = "git+file:///home/thegeneralist/infofeeder-bot";
|
||||||
url = "github:AlvaroParker/helium-nix";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
readlater-bot = {
|
calorie-tracker = {
|
||||||
url = "github:thegeneralist01/bookkeeper";
|
url = "git+file:///home/thegeneralist/calorie-tracker";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,10 @@ in {
|
||||||
"internal.${domain}" = {
|
"internal.${domain}" = {
|
||||||
group = "acme";
|
group = "acme";
|
||||||
};
|
};
|
||||||
"plex.${domain}" = {
|
"archive.${domain}" = {
|
||||||
group = "acme";
|
group = "acme";
|
||||||
};
|
};
|
||||||
"archive.${domain}" = {
|
"crawler.${domain}" = {
|
||||||
group = "acme";
|
group = "acme";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
41
hosts/thegeneralist-central/archive/crawler-site.nix
Normal file
41
hosts/thegeneralist-central/archive/crawler-site.nix
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
let
|
||||||
|
acmeDomain = "thegeneralist01.com";
|
||||||
|
domain = "crawler.${acmeDomain}";
|
||||||
|
|
||||||
|
ssl = {
|
||||||
|
forceSSL = true;
|
||||||
|
quic = true;
|
||||||
|
useACMEHost = domain;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.nginx.virtualHosts.${domain} = ssl // {
|
||||||
|
listen = [
|
||||||
|
{
|
||||||
|
addr = "100.86.129.23";
|
||||||
|
port = 443;
|
||||||
|
ssl = true;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
addr = "100.86.129.23";
|
||||||
|
port = 80;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://127.0.0.1:8001";
|
||||||
|
recommendedProxySettings = true;
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
|
||||||
|
# tell nginx not to buffer the response. send it as it comes.
|
||||||
|
proxy_buffering off;
|
||||||
|
|
||||||
|
# give jellyfin plenty of time to transcode
|
||||||
|
proxy_read_timeout 3600s;
|
||||||
|
proxy_send_timeout 3600s;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ let
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./archivebox.nix ];
|
imports = [ ./archivebox.nix ./crawler-site.nix ];
|
||||||
|
|
||||||
services.nginx.virtualHosts.${domain} = ssl // {
|
services.nginx.virtualHosts.${domain} = ssl // {
|
||||||
listen = [
|
listen = [
|
||||||
|
|
|
||||||
99
hosts/thegeneralist-central/calorie-tracker/default.nix
Normal file
99
hosts/thegeneralist-central/calorie-tracker/default.nix
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
{ pkgs, inputs, ... }:
|
||||||
|
let
|
||||||
|
sourceDir = "${inputs.calorie-tracker}";
|
||||||
|
appDir = "/var/lib/calorie-tracker/app";
|
||||||
|
dataDir = "/var/lib/calorie-tracker";
|
||||||
|
port = 4322;
|
||||||
|
|
||||||
|
acmeDomain = "thegeneralist01.com";
|
||||||
|
domain = "calorie.${acmeDomain}";
|
||||||
|
|
||||||
|
ssl = {
|
||||||
|
forceSSL = true;
|
||||||
|
quic = true;
|
||||||
|
useACMEHost = acmeDomain;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.services.calorie-tracker = {
|
||||||
|
description = "Calorie Tracker";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
|
||||||
|
environment = {
|
||||||
|
NODE_ENV = "production";
|
||||||
|
HOST = "127.0.0.1";
|
||||||
|
PORT = toString port;
|
||||||
|
DATABASE_URL = "file:${dataDir}/dev.db";
|
||||||
|
PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING = "1";
|
||||||
|
|
||||||
|
PRISMA_FMT_BINARY = "${pkgs.prisma-engines}/bin/prisma-fmt";
|
||||||
|
PRISMA_SCHEMA_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/schema-engine";
|
||||||
|
PRISMA_QUERY_ENGINE_BINARY = "${pkgs.prisma-engines}/bin/query-engine";
|
||||||
|
PRISMA_QUERY_ENGINE_LIBRARY = "${pkgs.prisma-engines}/lib/libquery_engine.node";
|
||||||
|
};
|
||||||
|
|
||||||
|
path = with pkgs; [
|
||||||
|
bash
|
||||||
|
coreutils
|
||||||
|
gnused
|
||||||
|
nodejs_22
|
||||||
|
prisma
|
||||||
|
prisma-engines
|
||||||
|
rsync
|
||||||
|
sqlite
|
||||||
|
];
|
||||||
|
|
||||||
|
preStart = ''
|
||||||
|
mkdir -p ${appDir}
|
||||||
|
rsync -a --delete --exclude ".git" --exclude "node_modules" --exclude "dist" --exclude ".astro" ${sourceDir}/ ${appDir}/
|
||||||
|
chmod -R u+rwX ${appDir}
|
||||||
|
|
||||||
|
cd ${appDir}
|
||||||
|
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
cp .env.example .env
|
||||||
|
fi
|
||||||
|
|
||||||
|
sed -i 's#^DATABASE_URL=.*#DATABASE_URL="file:${dataDir}/dev.db"#' .env
|
||||||
|
|
||||||
|
if [ ! -d node_modules ] || [ ! -d node_modules/@astrojs/node ] || [ ! -d node_modules/server-destroy ] || [ ! -d node_modules/@vite-pwa/astro ] || [ ! -d node_modules/@astrojs/check ]; then
|
||||||
|
npm ci --include=dev --no-fund --no-audit
|
||||||
|
fi
|
||||||
|
|
||||||
|
sqlite3 "${dataDir}/dev.db" < ${./schema.sql}
|
||||||
|
|
||||||
|
npm run prisma:generate
|
||||||
|
rm -rf dist
|
||||||
|
npm run build
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "thegeneralist";
|
||||||
|
Group = "users";
|
||||||
|
StateDirectory = "calorie-tracker";
|
||||||
|
StateDirectoryMode = "0750";
|
||||||
|
# Keep working dir on the guaranteed StateDirectory path so preStart can
|
||||||
|
# create ${appDir} on first boot/deploy before ExecStart runs.
|
||||||
|
WorkingDirectory = dataDir;
|
||||||
|
ExecStart = "${pkgs.nodejs_22}/bin/node ${appDir}/dist/server/entry.mjs";
|
||||||
|
KillMode = "mixed";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# services.nginx.virtualHosts.${domain} = ssl // {
|
||||||
|
# locations."/" = {
|
||||||
|
# proxyPass = "http://127.0.0.1:${toString port}";
|
||||||
|
# proxyWebsockets = true;
|
||||||
|
# recommendedProxySettings = true;
|
||||||
|
# extraConfig = ''
|
||||||
|
# proxy_read_timeout 300s;
|
||||||
|
# proxy_send_timeout 300s;
|
||||||
|
# '';
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
}
|
||||||
180
hosts/thegeneralist-central/calorie-tracker/schema.sql
Normal file
180
hosts/thegeneralist-central/calorie-tracker/schema.sql
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "User" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"username" TEXT NOT NULL UNIQUE,
|
||||||
|
"email" TEXT NOT NULL UNIQUE,
|
||||||
|
"passwordHash" TEXT NOT NULL,
|
||||||
|
"isAdmin" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"emailVerifiedAt" DATETIME,
|
||||||
|
"locale" TEXT NOT NULL DEFAULT 'en',
|
||||||
|
"dayCutoffMinutes" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"weekStartsOn" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"scheduledDeletionAt" DATETIME,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "Session" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"tokenHash" TEXT NOT NULL UNIQUE,
|
||||||
|
"rememberDevice" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"lastActiveAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"expiresAt" DATETIME NOT NULL,
|
||||||
|
"recentAuthAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "Session_userId_idx" ON "Session"("userId");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "Goal" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"userId" TEXT NOT NULL UNIQUE,
|
||||||
|
"type" TEXT NOT NULL DEFAULT 'MAINTAIN_WEIGHT',
|
||||||
|
"calorieFormula" TEXT NOT NULL DEFAULT 'MIFFLIN_ST_JEOR',
|
||||||
|
"dailyCalorieTarget" INTEGER,
|
||||||
|
"proteinGramsTarget" INTEGER,
|
||||||
|
"carbsGramsTarget" INTEGER,
|
||||||
|
"fatGramsTarget" INTEGER,
|
||||||
|
"adaptiveSuggestions" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"requiresApproval" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "UserSettings" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"userId" TEXT NOT NULL UNIQUE,
|
||||||
|
"waterGoalLiters" REAL NOT NULL DEFAULT 2,
|
||||||
|
"useMetricDistance" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"precisionMode" TEXT NOT NULL DEFAULT 'BASIC',
|
||||||
|
"weekStartConfigurable" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"remindersEnabled" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"reminderQuietHoursStart" TEXT DEFAULT '22:00',
|
||||||
|
"reminderQuietHoursEnd" TEXT DEFAULT '07:00',
|
||||||
|
"pwaInstallPromptDismissed" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"pwaUpdateToastEnabled" INTEGER NOT NULL DEFAULT 1,
|
||||||
|
"aiPhotoEstimationEnabled" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"aiPhotoConsentAt" DATETIME,
|
||||||
|
"aiPhotoConsentPolicy" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "Product" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"ownerUserId" TEXT,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"brand" TEXT,
|
||||||
|
"barcode" TEXT,
|
||||||
|
"qrCode" TEXT,
|
||||||
|
"region" TEXT,
|
||||||
|
"packageSizeLabel" TEXT,
|
||||||
|
"servingSizeLabel" TEXT,
|
||||||
|
"calories" REAL,
|
||||||
|
"protein" REAL,
|
||||||
|
"carbs" REAL,
|
||||||
|
"fat" REAL,
|
||||||
|
"source" TEXT NOT NULL DEFAULT 'MANUAL',
|
||||||
|
"isAiEstimated" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"isGlobal" INTEGER NOT NULL DEFAULT 0,
|
||||||
|
"publicationStatus" TEXT NOT NULL DEFAULT 'LOCAL_ONLY',
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"publishedAt" DATETIME,
|
||||||
|
FOREIGN KEY ("ownerUserId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "Product_ownerUserId_idx" ON "Product"("ownerUserId");
|
||||||
|
CREATE INDEX IF NOT EXISTS "Product_isGlobal_publicationStatus_idx" ON "Product"("isGlobal", "publicationStatus");
|
||||||
|
CREATE INDEX IF NOT EXISTS "Product_barcode_brand_region_idx" ON "Product"("barcode", "brand", "region");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "ProductSubmission" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"productId" TEXT NOT NULL,
|
||||||
|
"submittedById" TEXT NOT NULL,
|
||||||
|
"reviewedById" TEXT,
|
||||||
|
"labelPhotoUrl" TEXT,
|
||||||
|
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||||
|
"reason" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"reviewedAt" DATETIME,
|
||||||
|
FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY ("submittedById") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY ("reviewedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "ProductSubmission_productId_status_idx" ON "ProductSubmission"("productId", "status");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "ProductContribution" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"productId" TEXT NOT NULL,
|
||||||
|
"contributorId" TEXT NOT NULL,
|
||||||
|
"payloadJson" TEXT NOT NULL,
|
||||||
|
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"reviewedAt" DATETIME,
|
||||||
|
"reviewedById" TEXT,
|
||||||
|
FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY ("contributorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "ProductContribution_productId_status_idx" ON "ProductContribution"("productId", "status");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "ModerationAuditLog" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"actorUserId" TEXT NOT NULL,
|
||||||
|
"targetType" TEXT NOT NULL,
|
||||||
|
"targetId" TEXT NOT NULL,
|
||||||
|
"action" TEXT NOT NULL,
|
||||||
|
"reason" TEXT,
|
||||||
|
"beforeJson" TEXT,
|
||||||
|
"afterJson" TEXT,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY ("actorUserId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "ModerationAuditLog_targetType_targetId_idx" ON "ModerationAuditLog"("targetType", "targetId");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "MealEntry" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"productId" TEXT,
|
||||||
|
"mealType" TEXT NOT NULL,
|
||||||
|
"consumedAt" DATETIME NOT NULL,
|
||||||
|
"quantityValue" REAL NOT NULL,
|
||||||
|
"quantityUnit" TEXT NOT NULL,
|
||||||
|
"calories" REAL NOT NULL,
|
||||||
|
"protein" REAL NOT NULL,
|
||||||
|
"carbs" REAL NOT NULL,
|
||||||
|
"fat" REAL NOT NULL,
|
||||||
|
"snapshotJson" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
FOREIGN KEY ("productId") REFERENCES "Product"("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "MealEntry_userId_consumedAt_idx" ON "MealEntry"("userId", "consumedAt");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "WaterEntry" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"amountMl" INTEGER NOT NULL,
|
||||||
|
"consumedAt" DATETIME NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "WaterEntry_userId_consumedAt_idx" ON "WaterEntry"("userId", "consumedAt");
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "ActivityEntry" (
|
||||||
|
"id" TEXT NOT NULL PRIMARY KEY,
|
||||||
|
"userId" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"method" TEXT NOT NULL,
|
||||||
|
"durationMinutes" INTEGER,
|
||||||
|
"distanceKm" REAL,
|
||||||
|
"intensity" REAL,
|
||||||
|
"caloriesBurned" REAL NOT NULL,
|
||||||
|
"startedAt" DATETIME NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "ActivityEntry_userId_startedAt_idx" ON "ActivityEntry"("userId", "startedAt");
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
./cache
|
./cache
|
||||||
./archive
|
./archive
|
||||||
./forgejo
|
./forgejo
|
||||||
|
./calorie-tracker
|
||||||
];
|
];
|
||||||
|
|
||||||
age.secrets.password.file = ./password.age;
|
age.secrets.password.file = ./password.age;
|
||||||
|
|
@ -108,11 +109,6 @@
|
||||||
repo_path = "/home/thegeneralist/obsidian";
|
repo_path = "/home/thegeneralist/obsidian";
|
||||||
token_file = config.age.secrets.readlaterBotSyncToken.path;
|
token_file = config.age.secrets.readlaterBotSyncToken.path;
|
||||||
};
|
};
|
||||||
sync_x = {
|
|
||||||
source_project_path = "/home/thegeneralist/bookkeeper/vendor/extract-x-bookmarks";
|
|
||||||
python_bin = "/home/thegeneralist/bookkeeper/vendor/extract-x-bookmarks/.venv/bin/python3";
|
|
||||||
work_dir = "/home/thegeneralist/bookkeeper/.sync-x-work";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{ pkgs, lib, ... }:
|
{ pkgs, lib, ... }:
|
||||||
let
|
let
|
||||||
subdomains = [ "internal" "archive" "plex" ];
|
subdomains = [ "internal" "archive" "crawler" "r" "b" "s" "p" "q" "cloud" ];
|
||||||
|
|
||||||
mainZoneFile = pkgs.writeText "thegeneralist01.zone" ''
|
mainZoneFile = pkgs.writeText "thegeneralist01.zone" ''
|
||||||
$ORIGIN thegeneralist01.com.
|
$ORIGIN thegeneralist01.com.
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@
|
||||||
];
|
];
|
||||||
|
|
||||||
# fileSystems."/mnt/usb" = {
|
# fileSystems."/mnt/usb" = {
|
||||||
# device = "/dev/disk/by-label/TURTLEBAT";
|
# device = "/dev/disk/by-uuid/AADEEA03DEE9C7A1";
|
||||||
|
# fsType = "ntfs-3g";
|
||||||
# options = [
|
# options = [
|
||||||
# "rw"
|
# "rw"
|
||||||
# "noatime"
|
# "noatime"
|
||||||
|
|
|
||||||
|
|
@ -8,38 +8,14 @@ let
|
||||||
quic = true;
|
quic = true;
|
||||||
useACMEHost = domain;
|
useACMEHost = domain;
|
||||||
};
|
};
|
||||||
|
|
||||||
plexDebUrl = "http://thegeneralist01.com/plexmediaserver_1.43.0.10492-121068a07_arm64.deb";
|
|
||||||
plexDebSha256 = "1fkh09b46q70kicjprxf0v507idhg2jh3pk97nhbxj1jagkhgck2";
|
|
||||||
plex = pkgs.stdenv.mkDerivation {
|
|
||||||
pname = "plexmediaserver";
|
|
||||||
version = "1.43.0.10492-121068a07";
|
|
||||||
|
|
||||||
src = pkgs.fetchurl {
|
|
||||||
url = plexDebUrl;
|
|
||||||
sha256 = plexDebSha256;
|
|
||||||
};
|
|
||||||
|
|
||||||
nativeBuildInputs = [ pkgs.dpkg ];
|
|
||||||
|
|
||||||
unpackPhase = ''
|
|
||||||
runHook preUnpack
|
|
||||||
dpkg-deb -x $src .
|
|
||||||
runHook postUnpack
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
mkdir -p $out
|
|
||||||
cp -r usr/* $out/
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
plex
|
||||||
|
];
|
||||||
|
|
||||||
services.plex = {
|
services.plex = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = plex;
|
|
||||||
# openFirewall = true;
|
# openFirewall = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ in
|
||||||
"thegeneralist01.com" = "http://localhost:80";
|
"thegeneralist01.com" = "http://localhost:80";
|
||||||
"www.thegeneralist01.com" = "http://localhost:80";
|
"www.thegeneralist01.com" = "http://localhost:80";
|
||||||
"cache.thegeneralist01.com" = "http://localhost:80";
|
"cache.thegeneralist01.com" = "http://localhost:80";
|
||||||
|
"calorie.thegeneralist01.com" = "http://localhost:4322";
|
||||||
"git.thegeneralist01.com" = "http://localhost:3000";
|
"git.thegeneralist01.com" = "http://localhost:3000";
|
||||||
};
|
};
|
||||||
default = "http_status:404";
|
default = "http_status:404";
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
settings = {
|
settings = {
|
||||||
# theme = "tokyonight";
|
# theme = "tokyonight";
|
||||||
theme = config.theme.ghosttyTheme;
|
theme = config.theme.ghosttyTheme;
|
||||||
# theme = if config.onLinux then "GruvboxDarkHard" else "Gruvbox Dark Hard";
|
|
||||||
font-family = "Berkeley Mono";
|
font-family = "Berkeley Mono";
|
||||||
font-size = 16;
|
font-size = 16;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ in {
|
||||||
yq-go
|
yq-go
|
||||||
eza
|
eza
|
||||||
fzf
|
fzf
|
||||||
fd
|
|
||||||
gh
|
gh
|
||||||
fastfetch
|
fastfetch
|
||||||
carapace
|
carapace
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ lib, config, ... }: {
|
{ lib, ... }: {
|
||||||
options.theme = {
|
options.theme = {
|
||||||
batTheme = lib.mkOption {
|
batTheme = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
ghosttyTheme = lib.mkOption {
|
ghosttyTheme = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = if config.onLinux then "GruvboxDarkHard" else "Gruvbox Dark Hard";
|
default = "Gruvbox Dark Hard";
|
||||||
description = "Theme name for Ghostty.";
|
description = "Theme name for Ghostty.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ inputs, pkgs, lib, config, ...}: let
|
{ pkgs, lib, config, ...}: let
|
||||||
inherit (lib) attrValues;
|
inherit (lib) attrValues;
|
||||||
in {
|
in {
|
||||||
environment.systemPackages = attrValues {
|
environment.systemPackages = attrValues {
|
||||||
|
|
@ -11,11 +11,6 @@ in {
|
||||||
} ++ (if (!config.isServer) then (attrValues {
|
} ++ (if (!config.isServer) then (attrValues {
|
||||||
inherit (pkgs) protonup-qt
|
inherit (pkgs) protonup-qt
|
||||||
xsane
|
xsane
|
||||||
simple-scan
|
simple-scan;
|
||||||
|
}) else []);
|
||||||
obsidian
|
|
||||||
tor-browser;
|
|
||||||
}) else []) ++ (if (!config.isServer) then [
|
|
||||||
inputs.helium.packages.${pkgs.system}.default
|
|
||||||
] else []);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
{
|
|
||||||
services.tor = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
# WE DO NOT WANT GERMAN NODES ANYWHERE IN THE CIRCUIT!!!!
|
|
||||||
ExcludeExitNodes = "{de}";
|
|
||||||
ExcludeNodes = "{de}";
|
|
||||||
StrictNodes = 1;
|
|
||||||
|
|
||||||
# optionally also avoid unknown-geoip nodes
|
|
||||||
GeoIPExcludeUnknown = 1;
|
|
||||||
|
|
||||||
# listen on socks5 port for local apps (like transmission/qbittorrent)
|
|
||||||
SOCKSPort = "9050";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
services.transmission = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
proxy = "socks5://127.0.0.1:9050"; # assuming tor daemon
|
|
||||||
proxy-auth-enabled = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
{ pkgs, lib, ... }: let
|
{ pkgs, lib, config, ... }: let
|
||||||
inherit (lib) optionalAttrs;
|
inherit (lib) optionalAttrs;
|
||||||
in {
|
in {
|
||||||
virtualisation.vmware.guest.enable = true;
|
virtualisation.vmware.guest.enable = true;
|
||||||
|
|
||||||
environment.systemPackages = [ pkgs.fuzzel ];
|
environment.systemPackages = [ pkgs.fuzzel ];
|
||||||
programs.niri.enable = true;
|
programs.niri.enable = config.isServer;
|
||||||
|
|
||||||
services.xserver = {
|
services.xserver = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
@ -24,7 +24,7 @@ in {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
windowManager.i3 = optionalAttrs (false) {
|
windowManager.i3 = optionalAttrs (!config.isServer) {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.i3;
|
package = pkgs.i3;
|
||||||
configFile = ../dotfiles/i3/config;
|
configFile = ../dotfiles/i3/config;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue