Add hard zero

This commit is contained in:
2026-06-23 19:28:14 +01:00
parent 0ade78e919
commit b4a3f6c24d
5 changed files with 486 additions and 1 deletions
+43
View File
@@ -0,0 +1,43 @@
CREATE TABLE "Settings" (
"id" boolean PRIMARY KEY DEFAULT true NOT NULL,
"hardZeroAt" timestamp (3),
CONSTRAINT "Settings_singleton" CHECK ("id")
);
--> statement-breakpoint
INSERT INTO "Settings" ("id") VALUES (true);
--> statement-breakpoint
-- secondsSince counts from the latest of last execution, task creation, and the hard-zero
-- baseline. GREATEST ignores NULLs, so a NULL hardZeroAt has no effect.
DROP VIEW "TaskPeriod";
--> statement-breakpoint
CREATE VIEW "TaskPeriod" AS
SELECT *, ("secondsSince" / period) AS "urgency" FROM (
SELECT
"Task".id,
(("everyN" * (CASE "Task"."everySpan"
WHEN 'HOUR' THEN 3600
WHEN 'DAY' THEN 86400
WHEN 'WEEK' THEN 604800
WHEN 'MONTH' THEN 2629746
WHEN 'YEAR' THEN 31556952
WHEN 'DECADE' THEN 315569520
WHEN 'CENTURY' THEN 3155695200
ELSE 31556952
END)) / n) AS "period",
"Execution".id AS "latestExecutionId",
EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - GREATEST(
COALESCE("Execution".date, "Task"."createdAt"),
(SELECT "hardZeroAt" FROM "Settings")
))) AS "secondsSince"
FROM
"Task"
LEFT JOIN (
SELECT
"Execution".id,
"Execution"."taskId",
"Execution".date,
ROW_NUMBER() OVER (PARTITION BY "Execution"."taskId" ORDER BY "Execution".date DESC) AS rn
FROM
"Execution"
) AS "Execution" ON "Task".id = "Execution"."taskId" AND "Execution".rn = 1
) sub;
+410
View File
@@ -0,0 +1,410 @@
{
"id": "419b9723-6f92-4a7a-b4a7-1982c6e978f5",
"prevId": "87630719-c657-471c-b37a-a81fecf27978",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.Division": {
"name": "Division",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"Division_name_key": {
"name": "Division_name_key",
"nullsNotDistinct": false,
"columns": ["name"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Execution": {
"name": "Execution",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"taskId": {
"name": "taskId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"personId": {
"name": "personId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"date": {
"name": "date",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": true
},
"effort": {
"name": "effort",
"type": "double precision",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Execution_taskId_Task_id_fk": {
"name": "Execution_taskId_Task_id_fk",
"tableFrom": "Execution",
"tableTo": "Task",
"columnsFrom": ["taskId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
},
"Execution_personId_Person_id_fk": {
"name": "Execution_personId_Person_id_fk",
"tableFrom": "Execution",
"tableTo": "Person",
"columnsFrom": ["personId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Person": {
"name": "Person",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"Person_name_key": {
"name": "Person_name_key",
"nullsNotDistinct": false,
"columns": ["name"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Session": {
"name": "Session",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"expiresAt": {
"name": "expiresAt",
"type": "timestamp (3) with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Session_userId_User_id_fk": {
"name": "Session_userId_User_id_fk",
"tableFrom": "Session",
"tableTo": "User",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.Settings": {
"name": "Settings",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "boolean",
"primaryKey": true,
"notNull": true,
"default": true
},
"hardZeroAt": {
"name": "hardZeroAt",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {
"Settings_singleton": {
"name": "Settings_singleton",
"value": "\"id\""
}
},
"isRLSEnabled": false
},
"public.Task": {
"name": "Task",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"n": {
"name": "n",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"everyN": {
"name": "everyN",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"everySpan": {
"name": "everySpan",
"type": "Span",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"xp": {
"name": "xp",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"divisionId": {
"name": "divisionId",
"type": "text",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"Task_divisionId_Division_id_fk": {
"name": "Task_divisionId_Division_id_fk",
"tableFrom": "Task",
"tableTo": "Division",
"columnsFrom": ["divisionId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"Task_divisionId_name_key": {
"name": "Task_divisionId_name_key",
"nullsNotDistinct": false,
"columns": ["divisionId", "name"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"public.User": {
"name": "User",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"passwordHash": {
"name": "passwordHash",
"type": "text",
"primaryKey": false,
"notNull": true
},
"personId": {
"name": "personId",
"type": "text",
"primaryKey": false,
"notNull": true
},
"createdAt": {
"name": "createdAt",
"type": "timestamp (3)",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"User_personId_Person_id_fk": {
"name": "User_personId_Person_id_fk",
"tableFrom": "User",
"tableTo": "Person",
"columnsFrom": ["personId"],
"columnsTo": ["id"],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"User_username_key": {
"name": "User_username_key",
"nullsNotDistinct": false,
"columns": ["username"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {
"public.Span": {
"name": "Span",
"schema": "public",
"values": ["HOUR", "DAY", "WEEK", "MONTH", "YEAR", "DECADE", "CENTURY"]
}
},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {
"public.TaskPeriod": {
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"latestExecutionId": {
"name": "latestExecutionId",
"type": "text",
"primaryKey": false,
"notNull": false
},
"period": {
"name": "period",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"secondsSince": {
"name": "secondsSince",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"urgency": {
"name": "urgency",
"type": "double precision",
"primaryKey": false,
"notNull": false
}
},
"name": "TaskPeriod",
"schema": "public",
"isExisting": true,
"materialized": false
}
},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
+7
View File
@@ -15,6 +15,13 @@
"when": 1781952453886,
"tag": "0001_task_period_view",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1782239032665,
"tag": "0002_hard_zero",
"breakpoints": true
}
]
}
+2
View File
@@ -6,6 +6,8 @@ import { runSeed } from './seed';
const sql = postgres(demoUrl, { max: 1 });
await sql`TRUNCATE "Execution", "Task", "Division", "Person", "Session", "User" RESTART IDENTITY CASCADE`;
// Settings holds the singleton row, so clear it in place rather than truncating.
await sql`UPDATE "Settings" SET "hardZeroAt" = NULL`;
await sql.end();
await runSeed(demoUrl, { demo: true });
+24 -1
View File
@@ -1,5 +1,16 @@
import { relations, sql } from 'drizzle-orm';
import { doublePrecision, integer, pgEnum, pgTable, pgView, text, timestamp, unique } from 'drizzle-orm/pg-core';
import {
boolean,
check,
doublePrecision,
integer,
pgEnum,
pgTable,
pgView,
text,
timestamp,
unique,
} from 'drizzle-orm/pg-core';
import { type Span, spans } from '@/lib/span-enum';
// Physical table/column names stay PascalCase / camelCase (quoted) to match the
@@ -47,6 +58,18 @@ export const execution = pgTable('Execution', {
effort: doublePrecision('effort').notNull(),
});
// Singleton: the CHECK pins id to true, so the PK admits exactly one row.
export const settings = pgTable(
'Settings',
{
id: boolean('id').primaryKey().default(true),
// Urgency baseline: any task not executed since this instant counts as urgency 0
// (see GREATEST in the TaskPeriod view). NULL applies no baseline.
hardZeroAt: timestamp('hardZeroAt', { precision: 3, mode: 'date' }),
},
() => [check('Settings_singleton', sql`"id"`)],
);
// Auth tables: only ever written/read on the real DB (see src/db/index.ts).
export const user = pgTable('User', {
id: text('id').primaryKey().default(sql`gen_random_uuid()`),