mirror of
https://github.com/thegeneralist01/config.git
synced 2026-03-07 10:59:55 +01:00
add calorie-tracker as external flake service
This commit is contained in:
parent
60215eb57c
commit
16ce3aebd9
6 changed files with 370 additions and 15 deletions
98
flake.lock
generated
98
flake.lock
generated
|
|
@ -44,6 +44,25 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"calorie-tracker": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1771307893,
|
||||||
|
"narHash": "sha256-wHBIQSFjo/KWcY9Xvq30wsVAaNGEgirwebFQjqujPiU=",
|
||||||
|
"ref": "refs/heads/master",
|
||||||
|
"rev": "977eeccd7f2702ae85ff562b4f8bd39c3cbb1898",
|
||||||
|
"revCount": 1,
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/thegeneralist/calorie-tracker"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/thegeneralist/calorie-tracker"
|
||||||
|
}
|
||||||
|
},
|
||||||
"fenix": {
|
"fenix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
|
@ -117,10 +136,28 @@
|
||||||
"type": "github"
|
"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": {
|
"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",
|
||||||
|
|
@ -233,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": {
|
||||||
|
|
@ -280,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=",
|
||||||
|
|
@ -297,23 +350,27 @@
|
||||||
},
|
},
|
||||||
"readlater-bot": {
|
"readlater-bot": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_2",
|
"flake-utils": "flake-utils_3",
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1770458808,
|
"lastModified": 1771250778,
|
||||||
"narHash": "sha256-Fs/DwFxitReM7PuN1aee8pcmRzST7wzX7WLeBK/lOAI=",
|
"narHash": "sha256-lmWwzbuMer8vjGXh37p79dSctaFNjTBW6Cp0T5R+ZiE=",
|
||||||
"path": "/home/thegeneralist/infofeeder-bot",
|
"ref": "refs/heads/master",
|
||||||
"type": "path"
|
"rev": "181c03915b93d21c5d15a1375d3bc621b2992700",
|
||||||
|
"revCount": 17,
|
||||||
|
"type": "git",
|
||||||
|
"url": "file:///home/thegeneralist/infofeeder-bot"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"path": "/home/thegeneralist/infofeeder-bot",
|
"type": "git",
|
||||||
"type": "path"
|
"url": "file:///home/thegeneralist/infofeeder-bot"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"agenix": "agenix",
|
"agenix": "agenix",
|
||||||
|
"calorie-tracker": "calorie-tracker",
|
||||||
"fenix": "fenix",
|
"fenix": "fenix",
|
||||||
"ghostty": "ghostty",
|
"ghostty": "ghostty",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
|
|
@ -321,7 +378,7 @@
|
||||||
"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"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -387,6 +444,21 @@
|
||||||
"type": "github"
|
"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": {
|
"zig": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": [
|
"flake-compat": [
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,11 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
readlater-bot = {
|
readlater-bot = {
|
||||||
url = "path:/home/thegeneralist/infofeeder-bot";
|
url = "git+file:///home/thegeneralist/infofeeder-bot";
|
||||||
|
};
|
||||||
|
|
||||||
|
calorie-tracker = {
|
||||||
|
url = "git+file:///home/thegeneralist/calorie-tracker";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
97
hosts/thegeneralist-central/calorie-tracker/default.nix
Normal file
97
hosts/thegeneralist-central/calorie-tracker/default.nix
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
{ 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}/
|
||||||
|
|
||||||
|
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 ]; then
|
||||||
|
npm ci --no-fund --no-audit
|
||||||
|
fi
|
||||||
|
|
||||||
|
sqlite3 "${dataDir}/dev.db" < ${./schema.sql}
|
||||||
|
|
||||||
|
npm run prisma:generate
|
||||||
|
if [ ! -f dist/server/entry.mjs ]; then
|
||||||
|
npm run build
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
User = "thegeneralist";
|
||||||
|
Group = "users";
|
||||||
|
StateDirectory = "calorie-tracker";
|
||||||
|
StateDirectoryMode = "0750";
|
||||||
|
WorkingDirectory = appDir;
|
||||||
|
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;
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,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";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue