diff --git a/flake.lock b/flake.lock index 1c41f87..3cc58f5 100644 --- a/flake.lock +++ b/flake.lock @@ -44,25 +44,6 @@ "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": { "inputs": { "nixpkgs": [ @@ -136,28 +117,10 @@ "type": "github" } }, - "flake-utils_3": { - "inputs": { - "systems": "systems_4" - }, - "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "ghostty": { "inputs": { "flake-compat": "flake-compat", - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils", "nixpkgs-stable": "nixpkgs-stable", "nixpkgs-unstable": "nixpkgs-unstable", "zig": "zig", @@ -270,11 +233,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1771008912, - "narHash": "sha256-gf2AmWVTs8lEq7z/3ZAsgnZDhWIckkb+ZnAo5RzSxJg=", + "lastModified": 1755186698, + "narHash": "sha256-wNO3+Ks2jZJ4nTHMuks+cxAiVBGNuEBXsT29Bz6HASo=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a82ccc39b39b621151d6732718e3e250109076fa", + "rev": "fbcf476f790d8a217c3eab4e12033dc4a0f6d23c", "type": "github" }, "original": { @@ -317,22 +280,6 @@ } }, "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": { "lastModified": 1769789167, "narHash": "sha256-kKB3bqYJU5nzYeIROI82Ef9VtTbu4uA3YydSk/Bioa8=", @@ -350,27 +297,23 @@ }, "readlater-bot": { "inputs": { - "flake-utils": "flake-utils_3", - "nixpkgs": "nixpkgs_3" + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1771250778, - "narHash": "sha256-lmWwzbuMer8vjGXh37p79dSctaFNjTBW6Cp0T5R+ZiE=", - "ref": "refs/heads/master", - "rev": "181c03915b93d21c5d15a1375d3bc621b2992700", - "revCount": 17, - "type": "git", - "url": "file:///home/thegeneralist/infofeeder-bot" + "lastModified": 1770458808, + "narHash": "sha256-Fs/DwFxitReM7PuN1aee8pcmRzST7wzX7WLeBK/lOAI=", + "path": "/home/thegeneralist/infofeeder-bot", + "type": "path" }, "original": { - "type": "git", - "url": "file:///home/thegeneralist/infofeeder-bot" + "path": "/home/thegeneralist/infofeeder-bot", + "type": "path" } }, "root": { "inputs": { "agenix": "agenix", - "calorie-tracker": "calorie-tracker", "fenix": "fenix", "ghostty": "ghostty", "home-manager": "home-manager", @@ -378,7 +321,7 @@ "homebrew-core": "homebrew-core", "nix-darwin": "nix-darwin", "nix-homebrew": "nix-homebrew", - "nixpkgs": "nixpkgs_2", + "nixpkgs": "nixpkgs", "readlater-bot": "readlater-bot" } }, @@ -444,21 +387,6 @@ "type": "github" } }, - "systems_4": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "zig": { "inputs": { "flake-compat": [ diff --git a/flake.nix b/flake.nix index 40029a4..e72df1d 100644 --- a/flake.nix +++ b/flake.nix @@ -43,11 +43,7 @@ }; readlater-bot = { - url = "git+file:///home/thegeneralist/infofeeder-bot"; - }; - - calorie-tracker = { - url = "git+file:///home/thegeneralist/calorie-tracker"; + url = "path:/home/thegeneralist/infofeeder-bot"; }; }; diff --git a/hosts/thegeneralist-central/calorie-tracker/default.nix b/hosts/thegeneralist-central/calorie-tracker/default.nix deleted file mode 100644 index 9864eb2..0000000 --- a/hosts/thegeneralist-central/calorie-tracker/default.nix +++ /dev/null @@ -1,99 +0,0 @@ -{ 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; - # ''; - # }; - # }; -} diff --git a/hosts/thegeneralist-central/calorie-tracker/schema.sql b/hosts/thegeneralist-central/calorie-tracker/schema.sql deleted file mode 100644 index 7c2c1a8..0000000 --- a/hosts/thegeneralist-central/calorie-tracker/schema.sql +++ /dev/null @@ -1,180 +0,0 @@ -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"); diff --git a/hosts/thegeneralist-central/configuration.nix b/hosts/thegeneralist-central/configuration.nix index ba6f7e7..474339a 100644 --- a/hosts/thegeneralist-central/configuration.nix +++ b/hosts/thegeneralist-central/configuration.nix @@ -17,7 +17,6 @@ ./cache ./archive ./forgejo - ./calorie-tracker ]; age.secrets.password.file = ./password.age; diff --git a/hosts/thegeneralist-central/site.nix b/hosts/thegeneralist-central/site.nix index a45a3ab..538f1ad 100644 --- a/hosts/thegeneralist-central/site.nix +++ b/hosts/thegeneralist-central/site.nix @@ -1,7 +1,7 @@ { config, pkgs, ... }: let domain = "thegeneralist01.com"; - family_domain = builtins.getEnv "FAMILY_DOMAIN"; + family_domain = builtins.getEnv "FAMILY_DOMAIN"; ssl = { quic = true; @@ -101,7 +101,6 @@ in "thegeneralist01.com" = "http://localhost:80"; "www.thegeneralist01.com" = "http://localhost:80"; "cache.thegeneralist01.com" = "http://localhost:80"; - "calorie.thegeneralist01.com" = "http://localhost:4322"; "git.thegeneralist01.com" = "http://localhost:3000"; }; default = "http_status:404";