From de18e525cdb2b84c37fd90f53db356061729bf95 Mon Sep 17 00:00:00 2001 From: Max Norman <27299284+maxn990@users.noreply.github.com> Date: Sun, 3 Aug 2025 17:11:31 -0400 Subject: [PATCH 01/98] setup & create task, category --- .gitignore | 1 + apps/backend/src/app.module.ts | 23 +-- apps/backend/src/data-source.ts | 22 ++ .../src/migrations/1754254886189-add_task.ts | 19 ++ apps/backend/src/task/task.controller.ts | 19 ++ apps/backend/src/task/task.module.ts | 13 ++ apps/backend/src/task/task.service.ts | 12 ++ apps/backend/src/task/types/category.ts | 20 ++ apps/backend/src/task/types/task.entity.ts | 41 ++++ example.env | 5 + package.json | 13 +- yarn.lock | 189 +++++++++++------- 12 files changed, 277 insertions(+), 100 deletions(-) create mode 100644 apps/backend/src/data-source.ts create mode 100644 apps/backend/src/migrations/1754254886189-add_task.ts create mode 100644 apps/backend/src/task/task.controller.ts create mode 100644 apps/backend/src/task/task.module.ts create mode 100644 apps/backend/src/task/task.service.ts create mode 100644 apps/backend/src/task/types/category.ts create mode 100644 apps/backend/src/task/types/task.entity.ts create mode 100644 example.env diff --git a/.gitignore b/.gitignore index 6033c03e..ac8cb93a 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ Thumbs.db # Environment file *.env *.env.* +!example.env \ No newline at end of file diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 0a6461c8..54fb044e 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -3,28 +3,11 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { UsersModule } from './users/users.module'; -import { AuthModule } from './auth/auth.module'; -import { PluralNamingStrategy } from './strategies/plural-naming.strategy'; +import { TaskModule } from './task/task.module'; +import AppDataSource from './data-source'; @Module({ - imports: [ - TypeOrmModule.forRoot({ - type: 'mongodb', - host: '127.0.0.1', - port: 27017, - database: 'c4cOpsTest', - // username: 'root', - // password: 'root', - autoLoadEntities: true, - // entities: [join(__dirname, '**/**.entity.{ts,js}')], - // Setting synchronize: true shouldn't be used in production - otherwise you can lose production data - synchronize: true, - namingStrategy: new PluralNamingStrategy(), - }), - UsersModule, - AuthModule, - ], + imports: [TypeOrmModule.forRoot(AppDataSource.options), TaskModule], controllers: [AppController], providers: [AppService], }) diff --git a/apps/backend/src/data-source.ts b/apps/backend/src/data-source.ts new file mode 100644 index 00000000..bccc30f9 --- /dev/null +++ b/apps/backend/src/data-source.ts @@ -0,0 +1,22 @@ +import { DataSource } from 'typeorm'; +import { PluralNamingStrategy } from './strategies/plural-naming.strategy'; +import { Task } from './task/types/task.entity'; +import * as dotenv from 'dotenv'; + +dotenv.config(); + +const AppDataSource = new DataSource({ + type: 'postgres', + host: process.env.NX_DB_HOST, + port: parseInt(process.env.NX_DB_PORT as string, 10), + username: process.env.NX_DB_USERNAME, + password: process.env.NX_DB_PASSWORD, + database: process.env.NX_DB_DATABASE, + entities: [Task], + migrations: ['apps/backend/src/migrations/*.ts'], + // Setting synchronize: true shouldn't be used in production - otherwise you can lose production data + synchronize: true, + namingStrategy: new PluralNamingStrategy(), +}); + +export default AppDataSource; diff --git a/apps/backend/src/migrations/1754254886189-add_task.ts b/apps/backend/src/migrations/1754254886189-add_task.ts new file mode 100644 index 00000000..973decba --- /dev/null +++ b/apps/backend/src/migrations/1754254886189-add_task.ts @@ -0,0 +1,19 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class AddTask1754254886189 implements MigrationInterface { + name = 'AddTask1754254886189'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "public"."tasks_category_enum" AS ENUM('Draft', 'To Do', 'In Progress', 'Completed')`, + ); + await queryRunner.query( + `CREATE TABLE "task" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "description" character varying NOT NULL, "dateCreated" TIMESTAMP NOT NULL DEFAULT now(), "dueDate" TIMESTAMP, "labels" jsonb NOT NULL, "category" "public"."tasks_category_enum" NOT NULL DEFAULT 'Draft', CONSTRAINT "PK_8d12ff38fcc62aaba2cab748772" PRIMARY KEY ("id"))`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP TABLE "task"`); + await queryRunner.query(`DROP TYPE "public"."tasks_category_enum"`); + } +} diff --git a/apps/backend/src/task/task.controller.ts b/apps/backend/src/task/task.controller.ts new file mode 100644 index 00000000..f40e373d --- /dev/null +++ b/apps/backend/src/task/task.controller.ts @@ -0,0 +1,19 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, + Query, +} from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { TasksService } from './task.service'; +import { Task } from './types/task.entity'; + +@ApiTags('tasks') +@Controller('tasks') +export class TasksController { + constructor(private readonly tasksService: TasksService) {} +} diff --git a/apps/backend/src/task/task.module.ts b/apps/backend/src/task/task.module.ts new file mode 100644 index 00000000..1a91ba7f --- /dev/null +++ b/apps/backend/src/task/task.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { TasksController } from './task.controller'; +import { TasksService } from './task.service'; +import { Task } from './types/task.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Task])], + controllers: [TasksController], + providers: [TasksService], + exports: [TasksService], +}) +export class TaskModule {} diff --git a/apps/backend/src/task/task.service.ts b/apps/backend/src/task/task.service.ts new file mode 100644 index 00000000..3add73e5 --- /dev/null +++ b/apps/backend/src/task/task.service.ts @@ -0,0 +1,12 @@ +import { Task } from './types/task.entity'; +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +@Injectable() +export class TasksService { + constructor( + @InjectRepository(Task) + private readonly taskRepository: Repository, + ) {} +} diff --git a/apps/backend/src/task/types/category.ts b/apps/backend/src/task/types/category.ts new file mode 100644 index 00000000..c2092001 --- /dev/null +++ b/apps/backend/src/task/types/category.ts @@ -0,0 +1,20 @@ +export enum TaskCategory { + DRAFT = 'Draft', + TODO = 'To Do', + IN_PROGRESS = 'In Progress', + COMPLETED = 'Completed', +} + +export const CATEGORY_DESCRIPTIONS: Record = { + [TaskCategory.DRAFT]: 'Tasks that are still being planned or outlined', + [TaskCategory.TODO]: 'Tasks that are ready to be worked on', + [TaskCategory.IN_PROGRESS]: 'Tasks that are currently being worked on', + [TaskCategory.COMPLETED]: 'Tasks that have been finished', +}; + +export const CATEGORY_COLORS: Record = { + [TaskCategory.DRAFT]: '#6B7280', // Gray + [TaskCategory.TODO]: '#3B82F6', // Blue + [TaskCategory.IN_PROGRESS]: '#F59E0B', // Orange + [TaskCategory.COMPLETED]: '#10B981', // Green +}; diff --git a/apps/backend/src/task/types/task.entity.ts b/apps/backend/src/task/types/task.entity.ts new file mode 100644 index 00000000..f7ced345 --- /dev/null +++ b/apps/backend/src/task/types/task.entity.ts @@ -0,0 +1,41 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, +} from 'typeorm'; +import { TaskCategory } from './category'; // Adjust path as needed + +export interface Label { + id: string; + name: string; + color?: string; +} + +@Entity('tasks') +export class Task { + @PrimaryGeneratedColumn() + id: number; + + @Column() + title: string; + + @Column() + description: string; + + @CreateDateColumn() + dateCreated: Date; + + @Column({ nullable: true }) + dueDate?: Date; + + @Column('jsonb') + labels: Label[]; + + @Column({ + type: 'enum', + enum: TaskCategory, + default: TaskCategory.DRAFT, + }) + category: TaskCategory; +} diff --git a/example.env b/example.env new file mode 100644 index 00000000..211b1472 --- /dev/null +++ b/example.env @@ -0,0 +1,5 @@ +NX_DB_HOST=localhost, +NX_DB_USERNAME=postgres, +NX_DB_PASSWORD=, +NX_DB_DATABASE=jumpstart, +NX_DB_PORT=5432, \ No newline at end of file diff --git a/package.json b/package.json index 3f851e45..4c063fa0 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,12 @@ "lint": "eslint apps/frontend --ext .ts,.tsx --fix && eslint apps/backend --ext .ts,.tsx --fix", "prepush": "yarn run format:check && yarn run lint:check", "prepush:fix": "yarn run format && yarn run lint", - "prepare": "husky install" + "prepare": "husky install", + "typeorm": "ts-node -r tsconfig-paths/register --project apps/backend/tsconfig.app.json ./node_modules/typeorm/cli.js", + "migration:generate": "npm run typeorm -- migration:generate apps/backend/src/migrations/$npm_config_name -d apps/backend/src/data-source.ts", + "migration:run": "npm run typeorm -- migration:run -d apps/backend/src/data-source.ts", + "migration:revert": "npm run typeorm -- migration:revert -d apps/backend/src/data-source.ts", + "migration:create": "npm run typeorm -- migration:create apps/backend/src/migrations/$npm_config_name" }, "private": true, "dependencies": { @@ -21,21 +26,23 @@ "@nestjs/platform-express": "^10.0.2", "@nestjs/swagger": "^7.1.12", "@nestjs/typeorm": "^10.0.0", - "@types/mongodb": "^4.0.7", + "@types/pg": "^8.15.5", "amazon-cognito-identity-js": "^6.3.5", "axios": "^1.5.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "global": "^4.4.0", "jwks-rsa": "^3.1.0", - "mongodb": "^6.1.0", "passport": "^0.6.0", "passport-jwt": "^4.0.1", + "pg": "^8.16.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.15.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.0", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "typeorm": "^0.3.17" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 90853e9d..75ce8f81 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2071,13 +2071,6 @@ resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA== -"@mongodb-js/saslprep@^1.1.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz#9a6c2516bc9188672c4d953ec99760ba49970da7" - integrity sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ== - dependencies: - sparse-bitfield "^3.0.3" - "@nestjs/cli@^10.1.17": version "10.2.1" resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-10.2.1.tgz#a1d32c28e188f0fb4c3f54235c55745de4c6dd7f" @@ -3380,13 +3373,6 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.4.tgz#a4ed836e069491414bab92c31fdea9e557aca0d9" integrity sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw== -"@types/mongodb@^4.0.7": - version "4.0.7" - resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-4.0.7.tgz#ebaa80c53b684ea52ccfe7721c0f5c9ef7b4f511" - integrity sha512-lPUYPpzA43baXqnd36cZ9xxorprybxXDzteVKCPAdp14ppHtFJHnXYvNpmBvtMUTb5fKXVv6sVbzo1LHkWhJlw== - dependencies: - mongodb "*" - "@types/node-forge@^1.3.0": version "1.3.8" resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.8.tgz#044ad98354ff309a031a55a40ad122f3be1ac2bb" @@ -3413,6 +3399,15 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.1.tgz#27f7559836ad796cea31acb63163b203756a5b4e" integrity sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng== +"@types/pg@^8.15.5": + version "8.15.5" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.15.5.tgz#ef43e0f33b62dac95cae2f042888ec7980b30c09" + integrity sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^2.2.0" + "@types/prop-types@*": version "15.7.9" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.9.tgz#b6f785caa7ea1fe4414d9df42ee0ab67f23d8a6d" @@ -3510,19 +3505,6 @@ resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.11.5.tgz#1911964fd5556b08d3479d1ded977c06f89a44a7" integrity sha512-xW4qsT4UIYILu+7ZrBnfQdBYniZrMLYYK3wN9M/NdeIHgBN5pZI2/8Q7UfdWIcr5RLJv/OGENsx91JIpUUoC7Q== -"@types/webidl-conversions@*": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.2.tgz#d703e2bf61d8b77a7669adcd8fdf98108155d594" - integrity sha512-uNv6b/uGRLlCVmelat2rA8bcVd3k/42mV2EmjhPh6JLkd35T5bgwR/t6xy7a9MWhd9sixIeBUzhBenvk3NO+DQ== - -"@types/whatwg-url@^8.2.1": - version "8.2.2" - resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz#749d5b3873e845897ada99be4448041d4cc39e63" - integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA== - dependencies: - "@types/node" "*" - "@types/webidl-conversions" "*" - "@types/ws@^8.5.5": version "8.5.8" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.8.tgz#13efec7bd439d0bdf2af93030804a94f163b1430" @@ -4623,11 +4605,6 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -bson@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/bson/-/bson-6.2.0.tgz#4b6acafc266ba18eeee111373c2699304a9ba0a3" - integrity sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q== - buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -8702,11 +8679,6 @@ memfs@^3.4.1, memfs@^3.4.3: dependencies: fs-monkey "^1.0.4" -memory-pager@^1.0.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" - integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -8873,23 +8845,6 @@ mlly@^1.2.0, mlly@^1.4.0: pkg-types "^1.0.3" ufo "^1.3.0" -mongodb-connection-string-url@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz#57901bf352372abdde812c81be47b75c6b2ec5cf" - integrity sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ== - dependencies: - "@types/whatwg-url" "^8.2.1" - whatwg-url "^11.0.0" - -mongodb@*, mongodb@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-6.2.0.tgz#2c9dcb3eeaf528ed850e94b3df392de6c6b0d7ab" - integrity sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA== - dependencies: - "@mongodb-js/saslprep" "^1.1.0" - bson "^6.2.0" - mongodb-connection-string-url "^2.6.0" - mrmime@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" @@ -9553,6 +9508,62 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== +pg-cloudflare@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.2.7.tgz#a1f3d226bab2c45ae75ea54d65ec05ac6cfafbef" + integrity sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg== + +pg-connection-string@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.9.1.tgz#bb1fd0011e2eb76ac17360dc8fa183b2d3465238" + integrity sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.10.1.tgz#481047c720be2d624792100cac1816f8850d31b2" + integrity sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg== + +pg-protocol@*, pg-protocol@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.10.3.tgz#ac9e4778ad3f84d0c5670583bab976ea0a34f69f" + integrity sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ== + +pg-types@2.2.0, pg-types@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.16.3: + version "8.16.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.16.3.tgz#160741d0b44fdf64680e45374b06d632e86c99fd" + integrity sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw== + dependencies: + pg-connection-string "^2.9.1" + pg-pool "^3.10.1" + pg-protocol "^1.10.3" + pg-types "2.2.0" + pgpass "1.0.5" + optionalDependencies: + pg-cloudflare "^1.2.7" + +pgpass@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -9884,6 +9895,28 @@ postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.27: picocolors "^1.0.0" source-map-js "^1.0.2" +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -10767,13 +10800,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sparse-bitfield@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" - integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== - dependencies: - memory-pager "^1.0.2" - spdy-transport@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" @@ -10797,6 +10823,11 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -11251,13 +11282,6 @@ tough-cookie@^4.1.2, tough-cookie@^4.1.3: universalify "^0.2.0" url-parse "^1.5.3" -tr46@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" - integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== - dependencies: - punycode "^2.1.1" - tr46@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469" @@ -11324,6 +11348,25 @@ ts-node@10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + tsconfig-paths-webpack-plugin@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.0.tgz#84008fc3e3e0658fdb0262758b07b4da6265ff1a" @@ -11342,7 +11385,7 @@ tsconfig-paths-webpack-plugin@4.1.0: enhanced-resolve "^5.7.0" tsconfig-paths "^4.1.2" -tsconfig-paths@4.2.0, tsconfig-paths@^4.0.0, tsconfig-paths@^4.1.2: +tsconfig-paths@4.2.0, tsconfig-paths@^4.0.0, tsconfig-paths@^4.1.2, tsconfig-paths@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== @@ -11904,14 +11947,6 @@ whatwg-mimetype@^3.0.0: resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== -whatwg-url@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" - integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== - dependencies: - tr46 "^3.0.0" - webidl-conversions "^7.0.0" - whatwg-url@^12.0.0, whatwg-url@^12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-12.0.1.tgz#fd7bcc71192e7c3a2a97b9a8d6b094853ed8773c" From da5e6f78eae2f0a8401e4a1ad0f16094c57060d3 Mon Sep 17 00:00:00 2001 From: Max Norman <27299284+maxn990@users.noreply.github.com> Date: Mon, 4 Aug 2025 21:29:58 -0400 Subject: [PATCH 02/98] fixed pr review comments --- apps/backend/src/migrations/1754254886189-add_task.ts | 2 +- apps/backend/src/task/types/task.entity.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/backend/src/migrations/1754254886189-add_task.ts b/apps/backend/src/migrations/1754254886189-add_task.ts index 973decba..450a6415 100644 --- a/apps/backend/src/migrations/1754254886189-add_task.ts +++ b/apps/backend/src/migrations/1754254886189-add_task.ts @@ -8,7 +8,7 @@ export class AddTask1754254886189 implements MigrationInterface { `CREATE TYPE "public"."tasks_category_enum" AS ENUM('Draft', 'To Do', 'In Progress', 'Completed')`, ); await queryRunner.query( - `CREATE TABLE "task" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "description" character varying NOT NULL, "dateCreated" TIMESTAMP NOT NULL DEFAULT now(), "dueDate" TIMESTAMP, "labels" jsonb NOT NULL, "category" "public"."tasks_category_enum" NOT NULL DEFAULT 'Draft', CONSTRAINT "PK_8d12ff38fcc62aaba2cab748772" PRIMARY KEY ("id"))`, + `CREATE TABLE "task" ("id" SERIAL NOT NULL, "title" character varying NOT NULL, "description" character varying, "dateCreated" TIMESTAMP NOT NULL DEFAULT now(), "dueDate" TIMESTAMP, "labels" jsonb NOT NULL DEFAULT '[]', "category" "public"."tasks_category_enum" NOT NULL DEFAULT 'Draft', CONSTRAINT "PK_8d12ff38fcc62aaba2cab748772" PRIMARY KEY ("id"))`, ); } diff --git a/apps/backend/src/task/types/task.entity.ts b/apps/backend/src/task/types/task.entity.ts index f7ced345..48b258f9 100644 --- a/apps/backend/src/task/types/task.entity.ts +++ b/apps/backend/src/task/types/task.entity.ts @@ -20,7 +20,7 @@ export class Task { @Column() title: string; - @Column() + @Column({ nullable: true }) description: string; @CreateDateColumn() @@ -29,7 +29,7 @@ export class Task { @Column({ nullable: true }) dueDate?: Date; - @Column('jsonb') + @Column('jsonb', { default: () => "'[]'" }) labels: Label[]; @Column({ From 73da3edf26057b20b8538de21e6746defa399ad6 Mon Sep 17 00:00:00 2001 From: amywng <147568742+amywng@users.noreply.github.com> Date: Wed, 6 Aug 2025 16:31:14 -0400 Subject: [PATCH 03/98] add label and migration to add tasks/labels tables --- apps/backend/src/app.module.ts | 9 +++- apps/backend/src/data-source.ts | 3 +- apps/backend/src/label/label.controller.ts | 19 +++++++ apps/backend/src/label/label.module.ts | 13 +++++ apps/backend/src/label/label.service.ts | 12 +++++ apps/backend/src/label/types/label.entity.ts | 20 ++++++++ .../src/migrations/1754254886189-add_task.ts | 19 ------- ...754510950040-add_label_relation_to_task.ts | 51 +++++++++++++++++++ apps/backend/src/task/types/task.entity.ts | 12 ++--- 9 files changed, 129 insertions(+), 29 deletions(-) create mode 100644 apps/backend/src/label/label.controller.ts create mode 100644 apps/backend/src/label/label.module.ts create mode 100644 apps/backend/src/label/label.service.ts create mode 100644 apps/backend/src/label/types/label.entity.ts delete mode 100644 apps/backend/src/migrations/1754254886189-add_task.ts create mode 100644 apps/backend/src/migrations/1754510950040-add_label_relation_to_task.ts diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 54fb044e..20b29c4b 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -3,11 +3,16 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { TaskModule } from './task/task.module'; import AppDataSource from './data-source'; +import { TaskModule } from './task/task.module'; +import { LabelModule } from './label/label.module'; @Module({ - imports: [TypeOrmModule.forRoot(AppDataSource.options), TaskModule], + imports: [ + TypeOrmModule.forRoot(AppDataSource.options), + TaskModule, + LabelModule, + ], controllers: [AppController], providers: [AppService], }) diff --git a/apps/backend/src/data-source.ts b/apps/backend/src/data-source.ts index bccc30f9..2af9a876 100644 --- a/apps/backend/src/data-source.ts +++ b/apps/backend/src/data-source.ts @@ -1,6 +1,7 @@ import { DataSource } from 'typeorm'; import { PluralNamingStrategy } from './strategies/plural-naming.strategy'; import { Task } from './task/types/task.entity'; +import { Label } from './label/types/label.entity'; import * as dotenv from 'dotenv'; dotenv.config(); @@ -12,7 +13,7 @@ const AppDataSource = new DataSource({ username: process.env.NX_DB_USERNAME, password: process.env.NX_DB_PASSWORD, database: process.env.NX_DB_DATABASE, - entities: [Task], + entities: [Task, Label], migrations: ['apps/backend/src/migrations/*.ts'], // Setting synchronize: true shouldn't be used in production - otherwise you can lose production data synchronize: true, diff --git a/apps/backend/src/label/label.controller.ts b/apps/backend/src/label/label.controller.ts new file mode 100644 index 00000000..ec4f78d9 --- /dev/null +++ b/apps/backend/src/label/label.controller.ts @@ -0,0 +1,19 @@ +import { + Controller, + Get, + Post, + Body, + Patch, + Param, + Delete, + Query, +} from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; +import { LabelsService } from './label.service'; +import { Label } from './types/label.entity'; + +@ApiTags('labels') +@Controller('labels') +export class LabelsController { + constructor(private readonly labelsService: LabelsService) {} +} diff --git a/apps/backend/src/label/label.module.ts b/apps/backend/src/label/label.module.ts new file mode 100644 index 00000000..1a837ab1 --- /dev/null +++ b/apps/backend/src/label/label.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Label } from './types/label.entity'; +import { LabelsService } from './label.service'; +import { LabelsController } from './label.controller'; + +@Module({ + imports: [TypeOrmModule.forFeature([Label])], + providers: [LabelsService], + controllers: [LabelsController], + exports: [LabelsService], +}) +export class LabelModule {} diff --git a/apps/backend/src/label/label.service.ts b/apps/backend/src/label/label.service.ts new file mode 100644 index 00000000..fba1ee90 --- /dev/null +++ b/apps/backend/src/label/label.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { Label } from './types/label.entity'; + +@Injectable() +export class LabelsService { + constructor( + @InjectRepository(Label) + private labelRepository: Repository