diff --git a/.phase6-state.json b/.phase6-state.json index ca3a3bf..de44e9d 100644 --- a/.phase6-state.json +++ b/.phase6-state.json @@ -1,6 +1,7 @@ { "completed_features": [ - "password-change" + "password-change", + "router-phase6" ], "current_feature": "router-phase6", "started_at": "2026-05-23T05:30:16.203066", diff --git a/GENERATION_LOG.md b/GENERATION_LOG.md index 7db71f0..be8af80 100644 --- a/GENERATION_LOG.md +++ b/GENERATION_LOG.md @@ -734,3 +734,25 @@ undefined - `05:36:46` **INFO** wrote 6341 chars in 54.4s (attempt 1) - `05:36:46` **INFO** Running tsc --noEmit on api… - `05:36:48` **INFO** tsc clean ✓ +- `05:36:48` **INFO** Committed feature router-phase6 +- `05:36:48` **INFO** Pushed: rc=0 + +## Phase-6 Run beendet (2026-05-23 05:36:48) + +- `05:36:48` **INFO** OK: 2, Attempted: 4, Total: 6 +- `05:36:48` **INFO** Running db:generate + db:migrate… +- `05:36:49` **INFO** db:generate rc=0: 4 columns 0 indexes 0 fks +projects 5 columns 0 indexes 1 fks +time_entries 7 columns 0 indexes 2 fks +users 6 columns 0 indexes 0 fks + +[✓] Your SQL migration file ➜ drizzle/0002_flowery_gressill.sql 🚀 + +- `05:36:49` **INFO** db:migrate rc=0: one/api@0.0.1 db:migrate /home/dark/Developer/EmberClone/apps/api +> tsx src/db/migrate.ts + +Running migrations... +Migrations completed successfully +Checking for admin user... +Admin user already exists + diff --git a/apps/api/drizzle/0002_flowery_gressill.sql b/apps/api/drizzle/0002_flowery_gressill.sql new file mode 100644 index 0000000..b0d4213 --- /dev/null +++ b/apps/api/drizzle/0002_flowery_gressill.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS "audit_log" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" uuid, + "action" text NOT NULL, + "resource_type" text, + "resource_id" text, + "metadata" text, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "audit_log" ADD CONSTRAINT "audit_log_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/apps/api/drizzle/meta/0002_snapshot.json b/apps/api/drizzle/meta/0002_snapshot.json new file mode 100644 index 0000000..16db9ef --- /dev/null +++ b/apps/api/drizzle/meta/0002_snapshot.json @@ -0,0 +1,381 @@ +{ + "id": "4e73cd21-8d36-4c83-924c-17928cb72db3", + "prevId": "fda40693-a479-48ca-b84b-678a33a4d995", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.app_settings": { + "name": "app_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workspace_name": { + "name": "workspace_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'EmberClone'" + }, + "default_billable": { + "name": "default_billable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "week_start": { + "name": "week_start", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "audit_log_user_id_users_id_fk": { + "name": "audit_log_user_id_users_id_fk", + "tableFrom": "audit_log", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.customers": { + "name": "customers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.projects": { + "name": "projects", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "customer_id": { + "name": "customer_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "projects_customer_id_customers_id_fk": { + "name": "projects_customer_id_customers_id_fk", + "tableFrom": "projects", + "tableTo": "customers", + "columnsFrom": [ + "customer_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.time_entries": { + "name": "time_entries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "start_time": { + "name": "start_time", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "time_entries_user_id_users_id_fk": { + "name": "time_entries_user_id_users_id_fk", + "tableFrom": "time_entries", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "time_entries_project_id_projects_id_fk": { + "name": "time_entries_project_id_projects_id_fk", + "tableFrom": "time_entries", + "tableTo": "projects", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password_hash": { + "name": "password_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/apps/api/drizzle/meta/_journal.json b/apps/api/drizzle/meta/_journal.json index ef35286..92b0518 100644 --- a/apps/api/drizzle/meta/_journal.json +++ b/apps/api/drizzle/meta/_journal.json @@ -15,6 +15,13 @@ "when": 1779506775428, "tag": "0001_minor_fabian_cortez", "breakpoints": true + }, + { + "idx": 2, + "version": "7", + "when": 1779507409175, + "tag": "0002_flowery_gressill", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/web/src/lib/theme.ts b/apps/web/src/lib/theme.ts index aca94ab..5b3ada9 100644 --- a/apps/web/src/lib/theme.ts +++ b/apps/web/src/lib/theme.ts @@ -1,4 +1,4 @@ -import { create contexts, createContext, useContext, useEffect, useState } from 'react'; +import { createContext, useContext, useEffect, useState } from 'react'; type Theme = 'light' | 'dark';