feat: add Home page with user dashboard and habit tracking features

- Implemented Home component with user authentication and loading states.
- Created Welcome component for unauthenticated users with a sign-in option.
- Developed Dashboard component to display user's habits and progress.
- Added functionality for habit management, including adding, updating, and deleting habits.
- Integrated HabitChart and HabitHistory components for visual representation of habits.
- Introduced sharing functionality for progress via Discord integration.

feat: establish Discord sharing configuration and routes

- Added DiscordSharingConfig type and readDiscordSharingConfig function for environment variable management.
- Created sharing contracts for input validation and data structure.
- Implemented sharing routes for previewing and sending progress images to Discord.
- Added tests for sharing routes to ensure authentication and proper error handling.
This commit is contained in:
syntaxbullet
2026-09-04 17:48:54 +02:00
parent dde5e77317
commit ecc2620a4c
34 changed files with 4017 additions and 140 deletions

View File

@@ -0,0 +1,19 @@
CREATE TABLE `discord_connections` (
`user_id` text PRIMARY KEY NOT NULL,
`encrypted_webhook` text NOT NULL,
`name` text NOT NULL,
`channel_id` text NOT NULL,
`guild_id` text NOT NULL,
`updated_at` integer NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `discord_deliveries` (
`id` text PRIMARY KEY NOT NULL,
`user_id` text NOT NULL,
`image_hash` text NOT NULL,
`status` text NOT NULL,
`message_url` text,
`created_at` integer NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);

View File

@@ -0,0 +1 @@
DROP TABLE `discord_connections`;

View File

@@ -0,0 +1,823 @@
{
"version": "6",
"dialect": "sqlite",
"id": "480b54f2-4f2f-4200-8f18-22f28b38b62b",
"prevId": "0893a83a-3004-440a-8e89-3a30f26a578d",
"tables": {
"combined_charts": {
"name": "combined_charts",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"habit_ids": {
"name": "habit_ids",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"settings": {
"name": "settings",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"combined_charts_user_idx": {
"name": "combined_charts_user_idx",
"columns": [
"user_id"
],
"isUnique": false
}
},
"foreignKeys": {
"combined_charts_user_id_users_id_fk": {
"name": "combined_charts_user_id_users_id_fk",
"tableFrom": "combined_charts",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"discord_connections": {
"name": "discord_connections",
"columns": {
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"encrypted_webhook": {
"name": "encrypted_webhook",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"channel_id": {
"name": "channel_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"guild_id": {
"name": "guild_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"discord_connections_user_id_users_id_fk": {
"name": "discord_connections_user_id_users_id_fk",
"tableFrom": "discord_connections",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"discord_deliveries": {
"name": "discord_deliveries",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"image_hash": {
"name": "image_hash",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"message_url": {
"name": "message_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"discord_deliveries_user_id_users_id_fk": {
"name": "discord_deliveries_user_id_users_id_fk",
"tableFrom": "discord_deliveries",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habit_calendar_settings": {
"name": "habit_calendar_settings",
"columns": {
"habit_id": {
"name": "habit_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"settings": {
"name": "settings",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"habit_calendar_settings_habit_id_habits_id_fk": {
"name": "habit_calendar_settings_habit_id_habits_id_fk",
"tableFrom": "habit_calendar_settings",
"tableTo": "habits",
"columnsFrom": [
"habit_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habit_days": {
"name": "habit_days",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"habit_id": {
"name": "habit_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"revision_id": {
"name": "revision_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"ends_at": {
"name": "ends_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"count_set": {
"name": "count_set",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"count": {
"name": "count",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"done": {
"name": "done",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
}
},
"indexes": {
"habit_days_lookup_idx": {
"name": "habit_days_lookup_idx",
"columns": [
"habit_id",
"date",
"revision_id"
],
"isUnique": false
}
},
"foreignKeys": {
"habit_days_habit_id_habits_id_fk": {
"name": "habit_days_habit_id_habits_id_fk",
"tableFrom": "habit_days",
"tableTo": "habits",
"columnsFrom": [
"habit_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"habit_days_revision_id_habit_revisions_id_fk": {
"name": "habit_days_revision_id_habit_revisions_id_fk",
"tableFrom": "habit_days",
"tableTo": "habit_revisions",
"columnsFrom": [
"revision_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habit_revisions": {
"name": "habit_revisions",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"habit_id": {
"name": "habit_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"effective_date": {
"name": "effective_date",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"habit_revisions_date_idx": {
"name": "habit_revisions_date_idx",
"columns": [
"habit_id",
"effective_date",
"id"
],
"isUnique": false
}
},
"foreignKeys": {
"habit_revisions_habit_id_habits_id_fk": {
"name": "habit_revisions_habit_id_habits_id_fk",
"tableFrom": "habit_revisions",
"tableTo": "habits",
"columnsFrom": [
"habit_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habits": {
"name": "habits",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_date": {
"name": "created_date",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"materialized_through": {
"name": "materialized_through",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"habits_user_idx": {
"name": "habits_user_idx",
"columns": [
"user_id"
],
"isUnique": false
}
},
"foreignKeys": {
"habits_user_id_users_id_fk": {
"name": "habits_user_id_users_id_fk",
"tableFrom": "habits",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"progress_events": {
"name": "progress_events",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"day_id": {
"name": "day_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"occurrence_id": {
"name": "occurrence_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"before": {
"name": "before",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"after": {
"name": "after",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"progress_events_day_idx": {
"name": "progress_events_day_idx",
"columns": [
"day_id"
],
"isUnique": false
}
},
"foreignKeys": {
"progress_events_day_id_habit_days_id_fk": {
"name": "progress_events_day_id_habit_days_id_fk",
"tableFrom": "progress_events",
"tableTo": "habit_days",
"columnsFrom": [
"day_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"sessions": {
"name": "sessions",
"columns": {
"token_hash": {
"name": "token_hash",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"sessions_user_id_idx": {
"name": "sessions_user_id_idx",
"columns": [
"user_id"
],
"isUnique": false
},
"sessions_expires_at_idx": {
"name": "sessions_expires_at_idx",
"columns": [
"expires_at"
],
"isUnique": false
}
},
"foreignKeys": {
"sessions_user_id_users_id_fk": {
"name": "sessions_user_id_users_id_fk",
"tableFrom": "sessions",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"task_occurrences": {
"name": "task_occurrences",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"day_id": {
"name": "day_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"task_id": {
"name": "task_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"done": {
"name": "done",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"expired_at": {
"name": "expired_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"closed_at": {
"name": "closed_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"task_occurrences_day_idx": {
"name": "task_occurrences_day_idx",
"columns": [
"day_id"
],
"isUnique": false
}
},
"foreignKeys": {
"task_occurrences_day_id_habit_days_id_fk": {
"name": "task_occurrences_day_id_habit_days_id_fk",
"tableFrom": "task_occurrences",
"tableTo": "habit_days",
"columnsFrom": [
"day_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"discord_id": {
"name": "discord_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"global_name": {
"name": "global_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"avatar_hash": {
"name": "avatar_hash",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'UTC'"
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"users_discord_id_unique": {
"name": "users_discord_id_unique",
"columns": [
"discord_id"
],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -0,0 +1,757 @@
{
"version": "6",
"dialect": "sqlite",
"id": "8241efb4-d92c-4b72-ac08-a5b5c1cd4a18",
"prevId": "480b54f2-4f2f-4200-8f18-22f28b38b62b",
"tables": {
"combined_charts": {
"name": "combined_charts",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"habit_ids": {
"name": "habit_ids",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"settings": {
"name": "settings",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"combined_charts_user_idx": {
"name": "combined_charts_user_idx",
"columns": [
"user_id"
],
"isUnique": false
}
},
"foreignKeys": {
"combined_charts_user_id_users_id_fk": {
"name": "combined_charts_user_id_users_id_fk",
"tableFrom": "combined_charts",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"discord_deliveries": {
"name": "discord_deliveries",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"image_hash": {
"name": "image_hash",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"status": {
"name": "status",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"message_url": {
"name": "message_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"discord_deliveries_user_id_users_id_fk": {
"name": "discord_deliveries_user_id_users_id_fk",
"tableFrom": "discord_deliveries",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habit_calendar_settings": {
"name": "habit_calendar_settings",
"columns": {
"habit_id": {
"name": "habit_id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"settings": {
"name": "settings",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"habit_calendar_settings_habit_id_habits_id_fk": {
"name": "habit_calendar_settings_habit_id_habits_id_fk",
"tableFrom": "habit_calendar_settings",
"tableTo": "habits",
"columnsFrom": [
"habit_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habit_days": {
"name": "habit_days",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"habit_id": {
"name": "habit_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"revision_id": {
"name": "revision_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"date": {
"name": "date",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"ends_at": {
"name": "ends_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"count_set": {
"name": "count_set",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"count": {
"name": "count",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 0
},
"done": {
"name": "done",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
}
},
"indexes": {
"habit_days_lookup_idx": {
"name": "habit_days_lookup_idx",
"columns": [
"habit_id",
"date",
"revision_id"
],
"isUnique": false
}
},
"foreignKeys": {
"habit_days_habit_id_habits_id_fk": {
"name": "habit_days_habit_id_habits_id_fk",
"tableFrom": "habit_days",
"tableTo": "habits",
"columnsFrom": [
"habit_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"habit_days_revision_id_habit_revisions_id_fk": {
"name": "habit_days_revision_id_habit_revisions_id_fk",
"tableFrom": "habit_days",
"tableTo": "habit_revisions",
"columnsFrom": [
"revision_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habit_revisions": {
"name": "habit_revisions",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"habit_id": {
"name": "habit_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"effective_date": {
"name": "effective_date",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"config": {
"name": "config",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"habit_revisions_date_idx": {
"name": "habit_revisions_date_idx",
"columns": [
"habit_id",
"effective_date",
"id"
],
"isUnique": false
}
},
"foreignKeys": {
"habit_revisions_habit_id_habits_id_fk": {
"name": "habit_revisions_habit_id_habits_id_fk",
"tableFrom": "habit_revisions",
"tableTo": "habits",
"columnsFrom": [
"habit_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"habits": {
"name": "habits",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_date": {
"name": "created_date",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"materialized_through": {
"name": "materialized_through",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"habits_user_idx": {
"name": "habits_user_idx",
"columns": [
"user_id"
],
"isUnique": false
}
},
"foreignKeys": {
"habits_user_id_users_id_fk": {
"name": "habits_user_id_users_id_fk",
"tableFrom": "habits",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"progress_events": {
"name": "progress_events",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"day_id": {
"name": "day_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"occurrence_id": {
"name": "occurrence_id",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"before": {
"name": "before",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"after": {
"name": "after",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"progress_events_day_idx": {
"name": "progress_events_day_idx",
"columns": [
"day_id"
],
"isUnique": false
}
},
"foreignKeys": {
"progress_events_day_id_habit_days_id_fk": {
"name": "progress_events_day_id_habit_days_id_fk",
"tableFrom": "progress_events",
"tableTo": "habit_days",
"columnsFrom": [
"day_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"sessions": {
"name": "sessions",
"columns": {
"token_hash": {
"name": "token_hash",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"sessions_user_id_idx": {
"name": "sessions_user_id_idx",
"columns": [
"user_id"
],
"isUnique": false
},
"sessions_expires_at_idx": {
"name": "sessions_expires_at_idx",
"columns": [
"expires_at"
],
"isUnique": false
}
},
"foreignKeys": {
"sessions_user_id_users_id_fk": {
"name": "sessions_user_id_users_id_fk",
"tableFrom": "sessions",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"task_occurrences": {
"name": "task_occurrences",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"day_id": {
"name": "day_id",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"task_id": {
"name": "task_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"done": {
"name": "done",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"expired_at": {
"name": "expired_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"closed_at": {
"name": "closed_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"task_occurrences_day_idx": {
"name": "task_occurrences_day_idx",
"columns": [
"day_id"
],
"isUnique": false
}
},
"foreignKeys": {
"task_occurrences_day_id_habit_days_id_fk": {
"name": "task_occurrences_day_id_habit_days_id_fk",
"tableFrom": "task_occurrences",
"tableTo": "habit_days",
"columnsFrom": [
"day_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"users": {
"name": "users",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"discord_id": {
"name": "discord_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"global_name": {
"name": "global_name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"avatar_hash": {
"name": "avatar_hash",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"timezone": {
"name": "timezone",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'UTC'"
},
"created_at": {
"name": "created_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"users_discord_id_unique": {
"name": "users_discord_id_unique",
"columns": [
"discord_id"
],
"isUnique": true
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
},
"internal": {
"indexes": {}
}
}

View File

@@ -29,6 +29,20 @@
"when": 1788507928967,
"tag": "0003_finalize_occurrence_deadlines",
"breakpoints": true
},
{
"idx": 4,
"version": "6",
"when": 1788533580335,
"tag": "0004_low_carmella_unuscione",
"breakpoints": true
},
{
"idx": 5,
"version": "6",
"when": 1788536554543,
"tag": "0005_bored_firelord",
"breakpoints": true
}
]
}