From 37003a6a268a4d29f6d2e9912142f889e09ccf70 Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 17:43:48 +0600 Subject: [PATCH 01/19] Added Tanstack Query and Axios dependencies --- flightdrift-frontend/package-lock.json | 188 +++++++++++++++++++++++++ flightdrift-frontend/package.json | 2 + 2 files changed, 190 insertions(+) diff --git a/flightdrift-frontend/package-lock.json b/flightdrift-frontend/package-lock.json index c9cf838..d144009 100644 --- a/flightdrift-frontend/package-lock.json +++ b/flightdrift-frontend/package-lock.json @@ -11,8 +11,10 @@ "@fontsource-variable/inter": "^5.2.8", "@fontsource-variable/raleway": "^5.2.8", "@tailwindcss/vite": "^4.3.0", + "@tanstack/react-query": "^5.100.14", "@tanstack/react-router": "^1.169.2", "@tanstack/react-router-devtools": "^1.166.13", + "axios": "^1.16.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.17.0", @@ -3282,6 +3284,32 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/query-core": { + "version": "5.100.14", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.14.tgz", + "integrity": "sha512-5X41dGpxgeaHISCRW2oYwcSycZeULZzAunaudXT9ov1KOTj9xwt0CH6hbwqP1/z74ZWF7rYFnDpyYH07XFcZew==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.100.14", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.14.tgz", + "integrity": "sha512-oOr6aRdSFEwWhzxEkD/9ZcItM3+LjBSkeVmadWKwUssAHTsqd/7bOjWrX4AbvEkoEhgAxzN0Xk6H/aYzXiYBAw==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.100.14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@tanstack/react-router": { "version": "1.169.2", "resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.169.2.tgz", @@ -4144,6 +4172,49 @@ "node": ">=4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/babel-dead-code-elimination": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz", @@ -4569,6 +4640,18 @@ "dev": true, "license": "MIT" }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", @@ -4801,6 +4884,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -4991,6 +5083,21 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -5574,6 +5681,63 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -5825,6 +5989,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", @@ -7740,6 +7919,15 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/flightdrift-frontend/package.json b/flightdrift-frontend/package.json index 2264105..91baf73 100644 --- a/flightdrift-frontend/package.json +++ b/flightdrift-frontend/package.json @@ -18,8 +18,10 @@ "@fontsource-variable/inter": "^5.2.8", "@fontsource-variable/raleway": "^5.2.8", "@tailwindcss/vite": "^4.3.0", + "@tanstack/react-query": "^5.100.14", "@tanstack/react-router": "^1.169.2", "@tanstack/react-router-devtools": "^1.166.13", + "axios": "^1.16.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.17.0", From 927c0ec3872ea5858612526983a2ee98a7127d7a Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 17:56:18 +0600 Subject: [PATCH 02/19] Added Tanstack generated route tree to gitignore --- flightdrift-frontend/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/flightdrift-frontend/.gitignore b/flightdrift-frontend/.gitignore index 07e023a..d024b94 100644 --- a/flightdrift-frontend/.gitignore +++ b/flightdrift-frontend/.gitignore @@ -23,3 +23,4 @@ dist-ssr *.sln *.sw? .tanstack +routeTree.gen.ts From b226133be74ac8cfe8e54059a4a22c5b76d7936a Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 17:56:30 +0600 Subject: [PATCH 03/19] Added `code` field to the Project entity, API requests, and database schema --- .../Flightdrift/Project/Create Project.yml | 3 +++ api-collection/Flightdrift/Project/Edit Project.yml | 3 +++ api-collection/Flightdrift/Project/Get Projects.yml | 1 + db/migration/3. project.sql | 1 + flightdrift-backend/AGENTS.md | 13 +++++++------ .../dto/project/CreateProjectRequest.java | 4 ++++ .../flightdrift/dto/project/EditProjectRequest.java | 4 ++++ .../flightdrift/dto/project/ProjectResponse.java | 2 ++ .../com/flightdrift/flightdrift/entity/Project.java | 3 +++ .../flightdrift/service/ProjectService.java | 2 ++ 10 files changed, 30 insertions(+), 6 deletions(-) diff --git a/api-collection/Flightdrift/Project/Create Project.yml b/api-collection/Flightdrift/Project/Create Project.yml index 31f8620..488e85c 100644 --- a/api-collection/Flightdrift/Project/Create Project.yml +++ b/api-collection/Flightdrift/Project/Create Project.yml @@ -14,6 +14,7 @@ http: data: |- { "name": "Flightdrift", + "code": "ARTEMIS", "iconUrl": "https://example.com/project.png" } auth: inherit @@ -42,6 +43,7 @@ examples: data: |- { "name": "Flightdrift", + "code": "ARTEMIS", "iconUrl": "https://example.com/project.png" } response: @@ -60,6 +62,7 @@ examples: "project": { "id": "019e6a80-e269-7ddc-9e6b-d25eccfd192d", "name": "Flightdrift", + "code": "ARTEMIS", "iconUrl": "https://example.com/project.png", "organizationId": "019e6a80-6593-7416-8876-dec6b99510ab" } diff --git a/api-collection/Flightdrift/Project/Edit Project.yml b/api-collection/Flightdrift/Project/Edit Project.yml index 7af765c..f745449 100644 --- a/api-collection/Flightdrift/Project/Edit Project.yml +++ b/api-collection/Flightdrift/Project/Edit Project.yml @@ -14,6 +14,7 @@ http: data: |- { "name": "Flightdrift HQ", + "code": "ARTEMIS", "iconUrl": "https://example.com/project-updated.png" } auth: inherit @@ -34,6 +35,7 @@ examples: data: |- { "name": "Flightdrift HQ", + "code": "ARTEMIS", "iconUrl": "https://example.com/project-updated.png" } response: @@ -52,6 +54,7 @@ examples: "project": { "id": "019e6a80-e269-7ddc-9e6b-d25eccfd192d", "name": "Flightdrift HQ", + "code": "ARTEMIS", "iconUrl": "https://example.com/project-updated.png", "organizationId": "019e6a80-6593-7416-8876-dec6b99510ab" } diff --git a/api-collection/Flightdrift/Project/Get Projects.yml b/api-collection/Flightdrift/Project/Get Projects.yml index a2f870e..9a2c8e2 100644 --- a/api-collection/Flightdrift/Project/Get Projects.yml +++ b/api-collection/Flightdrift/Project/Get Projects.yml @@ -36,6 +36,7 @@ examples: { "id": "019e6a80-e269-7ddc-9e6b-d25eccfd192d", "name": "Flightdrift", + "code": "ARTEMIS", "iconUrl": "https://example.com/project.png", "organizationId": "019e6a80-6593-7416-8876-dec6b99510ab" } diff --git a/db/migration/3. project.sql b/db/migration/3. project.sql index 5df83ff..b631d35 100644 --- a/db/migration/3. project.sql +++ b/db/migration/3. project.sql @@ -6,6 +6,7 @@ CREATE TABLE project ( id UUID PRIMARY KEY DEFAULT uuidv7(), name VARCHAR(50) NOT NULL, + code VARCHAR(10) NOT NULL, icon_url VARCHAR(1024), organization_id UUID REFERENCES organization (id) NOT NULL, version BIGINT DEFAULT 0, diff --git a/flightdrift-backend/AGENTS.md b/flightdrift-backend/AGENTS.md index 37c5add..0385b95 100644 --- a/flightdrift-backend/AGENTS.md +++ b/flightdrift-backend/AGENTS.md @@ -2,12 +2,13 @@ This is a Java 25 Spring Boot 4 project for a kanban-inspired project management ## Rules for Development 1. Use Java 25 LTS features. -2. Do not try to compile and test unless I ask you to. -3. Use the `dto.com.flightdrift.flightdrift.ApiResponse` class for API responses. -4. Add new lines between each instance variables of a class. -5. Use Lombok and Jakarta persistence annotations where applicable. -6. Use Lombok's `@Builder` when creating entites. -7. DB related sql files can be found under `db/migration` +2. Compile to check for errors. +3. Do not run tests for now. +4. Use the `dto.com.flightdrift.flightdrift.ApiResponse` class for API responses. +5. Add new lines between each instance variable of a class. +6. Use Lombok and Jakarta persistence annotations where applicable. +7. Use Lombok's `@Builder` when creating entites. +8. DB related sql files can be found under `db/migration` ## Tools 1. Check if `rg` is available, if so use it, otherwise use `grep`. \ No newline at end of file diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/CreateProjectRequest.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/CreateProjectRequest.java index b38ae24..dcedc3f 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/CreateProjectRequest.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/CreateProjectRequest.java @@ -12,6 +12,10 @@ public record CreateProjectRequest( @Size(max = 50, message = "Name must not exceed 50 characters") String name, + @NotBlank(message = "Code is required") + @Size(max = 10, message = "Code must not exceed 10 characters") + String code, + @Size(max = 1024, message = "Icon URL must not exceed 1024 characters") String iconUrl ) { diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/EditProjectRequest.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/EditProjectRequest.java index cbc91ce..7ab4b29 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/EditProjectRequest.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/EditProjectRequest.java @@ -12,6 +12,10 @@ public record EditProjectRequest( @Size(max = 50, message = "Name must not exceed 50 characters") String name, + @NotBlank(message = "Code is required") + @Size(max = 10, message = "Code must not exceed 10 characters") + String code, + @Size(max = 1024, message = "Icon URL must not exceed 1024 characters") String iconUrl ) { diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/ProjectResponse.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/ProjectResponse.java index ffed2ad..d6e089d 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/ProjectResponse.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/project/ProjectResponse.java @@ -11,6 +11,7 @@ public record ProjectResponse( UUID id, String name, + String code, String iconUrl, UUID organizationId ) { @@ -18,6 +19,7 @@ public static ProjectResponse fromEntity(Project project) { return new ProjectResponse( project.getId(), project.getName(), + project.getCode(), project.getIconUrl(), project.getOrganization().getId() ); diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/entity/Project.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/entity/Project.java index 1e42c79..b52d2fd 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/entity/Project.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/entity/Project.java @@ -36,6 +36,9 @@ public class Project extends Auditable { @Column(nullable = false, length = 50) private String name; + @Column(nullable = false, length = 10) + private String code; + @Column(name = "icon_url", length = 1024) private String iconUrl; diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/service/ProjectService.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/service/ProjectService.java index 4e0e1d7..8bcae8e 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/service/ProjectService.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/service/ProjectService.java @@ -47,6 +47,7 @@ public ProjectResponse createProject(String username, UUID organizationId, Creat Project project = Project.builder() .name(request.name()) + .code(request.code()) .iconUrl(request.iconUrl()) .organization(organization) .build(); @@ -81,6 +82,7 @@ public ProjectResponse editProject(String username, UUID projectId, EditProjectR } project.setName(request.name()); + project.setCode(request.code()); project.setIconUrl(request.iconUrl()); project = projectRepository.save(project); From 5784e484e144925c5e366d52d927db49fd6ace3d Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 18:11:48 +0600 Subject: [PATCH 04/19] Added Zustand --- flightdrift-frontend/package-lock.json | 32 +++++++++++++++++++++++++- flightdrift-frontend/package.json | 3 ++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/flightdrift-frontend/package-lock.json b/flightdrift-frontend/package-lock.json index d144009..0511307 100644 --- a/flightdrift-frontend/package-lock.json +++ b/flightdrift-frontend/package-lock.json @@ -24,7 +24,8 @@ "shadcn": "^4.8.2", "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.0", - "tw-animate-css": "^1.4.0" + "tw-animate-css": "^1.4.0", + "zustand": "^5.0.14" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -9535,6 +9536,35 @@ "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } + }, + "node_modules/zustand": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.14.tgz", + "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/flightdrift-frontend/package.json b/flightdrift-frontend/package.json index 91baf73..01e9b90 100644 --- a/flightdrift-frontend/package.json +++ b/flightdrift-frontend/package.json @@ -31,7 +31,8 @@ "shadcn": "^4.8.2", "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.0", - "tw-animate-css": "^1.4.0" + "tw-animate-css": "^1.4.0", + "zustand": "^5.0.14" }, "devDependencies": { "@eslint/js": "^10.0.1", From 0c92ecde3cb36ac6e3ec28a9029003bc61fcfdcf Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 18:31:21 +0600 Subject: [PATCH 05/19] Updated OpenCollection --- api-collection/Flightdrift/Auth/Sign In.yml | 2 +- api-collection/Flightdrift/environments/Flightdrift-Dev.yml | 1 + api-collection/Flightdrift/opencollection.yml | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 api-collection/Flightdrift/environments/Flightdrift-Dev.yml diff --git a/api-collection/Flightdrift/Auth/Sign In.yml b/api-collection/Flightdrift/Auth/Sign In.yml index 535ffe1..b30be1d 100644 --- a/api-collection/Flightdrift/Auth/Sign In.yml +++ b/api-collection/Flightdrift/Auth/Sign In.yml @@ -20,7 +20,7 @@ runtime: code: |- var jsonData = res.getBody(); - bru.set("auth_token", jsonData.data.token); + bru.setEnvVar("auth_token", jsonData.data.token); settings: encodeUrl: true diff --git a/api-collection/Flightdrift/environments/Flightdrift-Dev.yml b/api-collection/Flightdrift/environments/Flightdrift-Dev.yml new file mode 100644 index 0000000..0d08bc8 --- /dev/null +++ b/api-collection/Flightdrift/environments/Flightdrift-Dev.yml @@ -0,0 +1 @@ +name: Flightdrift-Dev diff --git a/api-collection/Flightdrift/opencollection.yml b/api-collection/Flightdrift/opencollection.yml index 7d521c0..a8adc85 100644 --- a/api-collection/Flightdrift/opencollection.yml +++ b/api-collection/Flightdrift/opencollection.yml @@ -27,8 +27,6 @@ request: value: 019e6a80-e269-7ddc-9e6b-d25eccfd192d - name: item_id value: 019b7a23-58a7-72f0-bdea-b39d8ab32191 - - name: auth_token - value: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqYW1pdXMxOSIsImlhdCI6MTc3OTkwMjgxMiwiZXhwIjoxODY2MzAyODEyfQ.Y0Rca6ESQvV16n_VJxP4rzxVERvRaSzonuOFTfyD0Ytz1H4cMEnQ-crukQ0i0l_Bwf72m_aCUfqSamdABNB6Vg bundled: false extensions: bruno: From 64c705c0decebc07e7aee1659218a13dae5972ed Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 18:38:16 +0600 Subject: [PATCH 06/19] Added Tanstack Form dependency --- flightdrift-frontend/package-lock.json | 105 +++++++++++++++++++++++++ flightdrift-frontend/package.json | 1 + 2 files changed, 106 insertions(+) diff --git a/flightdrift-frontend/package-lock.json b/flightdrift-frontend/package-lock.json index 0511307..1f71214 100644 --- a/flightdrift-frontend/package-lock.json +++ b/flightdrift-frontend/package-lock.json @@ -11,6 +11,7 @@ "@fontsource-variable/inter": "^5.2.8", "@fontsource-variable/raleway": "^5.2.8", "@tailwindcss/vite": "^4.3.0", + "@tanstack/react-form": "^1.33.0", "@tanstack/react-query": "^5.100.14", "@tanstack/react-router": "^1.169.2", "@tanstack/react-router-devtools": "^1.166.13", @@ -3272,6 +3273,47 @@ "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, + "node_modules/@tanstack/devtools-event-client": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@tanstack/devtools-event-client/-/devtools-event-client-0.4.3.tgz", + "integrity": "sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw==", + "license": "MIT", + "bin": { + "intent": "bin/intent.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/form-core": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@tanstack/form-core/-/form-core-1.33.0.tgz", + "integrity": "sha512-AV4Pw9Dk4orFsuPBcDssfWMJFs+yMYBae7zZ4oTqrCf4ftNGQKxvrQRZeqKHG6A4TkiLeSvf2kzIjcVkrW7E6w==", + "license": "MIT", + "dependencies": { + "@tanstack/devtools-event-client": "^0.4.1", + "@tanstack/pacer-lite": "^0.1.1", + "@tanstack/store": "^0.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/form-core/node_modules/@tanstack/store": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.11.0.tgz", + "integrity": "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/history": { "version": "1.161.6", "resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.161.6.tgz", @@ -3285,6 +3327,19 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/pacer-lite": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@tanstack/pacer-lite/-/pacer-lite-0.1.1.tgz", + "integrity": "sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/query-core": { "version": "5.100.14", "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.14.tgz", @@ -3295,6 +3350,56 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/react-form": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-form/-/react-form-1.33.0.tgz", + "integrity": "sha512-unaee+VS4MvKo+s1dmgGUXI4902VeAhuaUbKsQbhFe3MceOpB3JpAUGCDpyzjQPXVFkFY0COKfLrUNX2XZYW4g==", + "license": "MIT", + "dependencies": { + "@tanstack/form-core": "1.33.0", + "@tanstack/react-store": "^0.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@tanstack/react-start": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-form/node_modules/@tanstack/react-store": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.11.0.tgz", + "integrity": "sha512-tX4YXh3PDkmpvGQWkWqKpzs/MSqbtuwY9dWdWhtV9Q50PmO+jOkUKIWIX4G85dwt7lxdHLXsiaEKPdKmC8F41w==", + "license": "MIT", + "dependencies": { + "@tanstack/store": "0.11.0", + "use-sync-external-store": "^1.6.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@tanstack/react-form/node_modules/@tanstack/store": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.11.0.tgz", + "integrity": "sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/react-query": { "version": "5.100.14", "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.100.14.tgz", diff --git a/flightdrift-frontend/package.json b/flightdrift-frontend/package.json index 01e9b90..5dccc12 100644 --- a/flightdrift-frontend/package.json +++ b/flightdrift-frontend/package.json @@ -18,6 +18,7 @@ "@fontsource-variable/inter": "^5.2.8", "@fontsource-variable/raleway": "^5.2.8", "@tailwindcss/vite": "^4.3.0", + "@tanstack/react-form": "^1.33.0", "@tanstack/react-query": "^5.100.14", "@tanstack/react-router": "^1.169.2", "@tanstack/react-router-devtools": "^1.166.13", From 99e2268249dc9f36a019445d54070448ca804355 Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 18:46:22 +0600 Subject: [PATCH 07/19] Added `userInfo` to sign-in response --- api-collection/Flightdrift/Auth/Sign In.yml | 8 +++++++- api-collection/Flightdrift/Auth/Signup.yml | 6 +++--- flightdrift-backend/AGENTS.md | 11 ++++++----- .../flightdrift/controller/AuthController.java | 14 +++++++++++++- .../flightdrift/dto/auth/TokenResponse.java | 5 ++++- .../flightdrift/dto/auth/UserInfoResponse.java | 15 +++++++++++++++ 6 files changed, 48 insertions(+), 11 deletions(-) create mode 100644 flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/UserInfoResponse.java diff --git a/api-collection/Flightdrift/Auth/Sign In.yml b/api-collection/Flightdrift/Auth/Sign In.yml index b30be1d..6277026 100644 --- a/api-collection/Flightdrift/Auth/Sign In.yml +++ b/api-collection/Flightdrift/Auth/Sign In.yml @@ -73,6 +73,12 @@ examples: "success": true, "message": "Signed in successfully", "data": { - "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqYW1pdXMxOSIsImlhdCI6MTc3OTkwMjgxMiwiZXhwIjoxODY2MzAyODEyfQ.Y0Rca6ESQvV16n_VJxP4rzxVERvRaSzonuOFTfyD0Ytz1H4cMEnQ-crukQ0i0l_Bwf72m_aCUfqSamdABNB6Vg" + "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqYW1pdXMxOSIsImlhdCI6MTc3OTkwMjgxMiwiZXhwIjoxODY2MzAyODEyfQ.Y0Rca6ESQvV16n_VJxP4rzxVERvRaSzonuOFTfyD0Ytz1H4cMEnQ-crukQ0i0l_Bwf72m_aCUfqSamdABNB6Vg", + "userInfo": { + "id": "0c71345a-0a0f-42a5-88dc-43616f65d5e3", + "name": "Jamius Siam", + "email": "jamius@example.com", + "username": "jamius19" + } } } diff --git a/api-collection/Flightdrift/Auth/Signup.yml b/api-collection/Flightdrift/Auth/Signup.yml index 942e769..4ec4892 100644 --- a/api-collection/Flightdrift/Auth/Signup.yml +++ b/api-collection/Flightdrift/Auth/Signup.yml @@ -11,7 +11,7 @@ http: data: |- { "name": "Jamius Siam", - "email": "jamiussiam@gmail.com", + "email": "jamius@example.com", "username": "jamius19", "password": "123" } @@ -69,9 +69,9 @@ examples: "success": true, "message": "Account created successfully", "data": { - "id": "019e6a79-5e97-7b4d-9f53-b7d0e4a3f96c", + "id": "019e73b4-33b7-74fd-ad65-3bd068e2e46c", "name": "Jamius Siam", - "email": "jamiussiam@gmail.com", + "email": "jamius@example.com", "username": "jamius19" } } diff --git a/flightdrift-backend/AGENTS.md b/flightdrift-backend/AGENTS.md index 0385b95..03aff15 100644 --- a/flightdrift-backend/AGENTS.md +++ b/flightdrift-backend/AGENTS.md @@ -2,13 +2,14 @@ This is a Java 25 Spring Boot 4 project for a kanban-inspired project management ## Rules for Development 1. Use Java 25 LTS features. -2. Compile to check for errors. +2. Compile to check for errors without running tests. 3. Do not run tests for now. 4. Use the `dto.com.flightdrift.flightdrift.ApiResponse` class for API responses. -5. Add new lines between each instance variable of a class. -6. Use Lombok and Jakarta persistence annotations where applicable. -7. Use Lombok's `@Builder` when creating entites. -8. DB related sql files can be found under `db/migration` +5. Update the OpenCollection files at `api-collection/Flightdrift` when adding/updating endpoints. +6. Add new lines between each instance variable of a class. +7. Use Lombok and Jakarta persistence annotations where applicable. +8. Use Lombok's `@Builder` when creating entities. +9. DB related SQL files can be found under `db/migration` ## Tools 1. Check if `rg` is available, if so use it, otherwise use `grep`. \ No newline at end of file diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/controller/AuthController.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/controller/AuthController.java index e2867f4..4756693 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/controller/AuthController.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/controller/AuthController.java @@ -15,6 +15,7 @@ import com.flightdrift.flightdrift.dto.auth.InvitationTokenResponse; import com.flightdrift.flightdrift.dto.auth.SignupResponse; import com.flightdrift.flightdrift.dto.auth.TokenResponse; +import com.flightdrift.flightdrift.dto.auth.UserInfoResponse; import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.security.SecurityRequirement; @@ -91,11 +92,22 @@ public ResponseEntity> signin(@Valid @RequestBody SigninRequest s UserDetails userDetails = userDetailsService.loadUserByUsername(signinRequest.username()); String token = jwtUtil.generateToken(userDetails); + Account account = accountRepository + .findByUsername(userDetails.getUsername()) + .orElseThrow(() -> new IllegalStateException("Authenticated account not found")); return ResponseEntity.ok(new ApiResponse<>( true, "Signed in successfully", - new TokenResponse(token) + new TokenResponse( + token, + new UserInfoResponse( + account.getId(), + account.getName(), + account.getEmail(), + account.getUsername() + ) + ) )); } diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/TokenResponse.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/TokenResponse.java index b331e65..ffc5893 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/TokenResponse.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/TokenResponse.java @@ -4,5 +4,8 @@ * Author: Jamius Siam * Since: 06/05/2026 */ -public record TokenResponse(String token) { +public record TokenResponse( + String token, + UserInfoResponse userInfo +) { } diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/UserInfoResponse.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/UserInfoResponse.java new file mode 100644 index 0000000..ddd7297 --- /dev/null +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/dto/auth/UserInfoResponse.java @@ -0,0 +1,15 @@ +package com.flightdrift.flightdrift.dto.auth; + +import java.util.UUID; + +/* + * Author: Jamius Siam + * Since: 29/05/2026 + */ +public record UserInfoResponse( + UUID id, + String name, + String email, + String username +) { +} From 088bc336d931b8f763300b08d4e354c9a820d15e Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 19:36:54 +0600 Subject: [PATCH 08/19] Added Tanstack Query ESLint plugin --- flightdrift-frontend/eslint.config.js | 2 ++ flightdrift-frontend/package-lock.json | 24 ++++++++++++++++++++++++ flightdrift-frontend/package.json | 1 + 3 files changed, 27 insertions(+) diff --git a/flightdrift-frontend/eslint.config.js b/flightdrift-frontend/eslint.config.js index c127865..ab6d674 100644 --- a/flightdrift-frontend/eslint.config.js +++ b/flightdrift-frontend/eslint.config.js @@ -8,8 +8,10 @@ import reactHooks from "eslint-plugin-react-hooks"; import reactRefresh from "eslint-plugin-react-refresh"; import tseslint from "typescript-eslint"; import { defineConfig, globalIgnores } from "eslint/config"; +import pluginQuery from "@tanstack/eslint-plugin-query"; export default defineConfig([ + ...pluginQuery.configs["flat/recommended"], globalIgnores(["dist"]), { files: ["**/*.{ts,tsx}"], diff --git a/flightdrift-frontend/package-lock.json b/flightdrift-frontend/package-lock.json index 1f71214..026ee01 100644 --- a/flightdrift-frontend/package-lock.json +++ b/flightdrift-frontend/package-lock.json @@ -30,6 +30,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@tanstack/eslint-plugin-query": "^5.100.14", "@tanstack/router-cli": "^1.166.42", "@tanstack/router-plugin": "^1.167.34", "@types/node": "^24.12.2", @@ -3289,6 +3290,29 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/eslint-plugin-query": { + "version": "5.100.14", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.100.14.tgz", + "integrity": "sha512-NbpiBCmeHTRuVHeV5+U+1bzmxyTW5Dzp2sCeE6Hx+ZJTJWFK9dsm8VZmRc7LQP9/ZORsF620PvgUk67AwiBo4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.58.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": "^5.4.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@tanstack/form-core": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/@tanstack/form-core/-/form-core-1.33.0.tgz", diff --git a/flightdrift-frontend/package.json b/flightdrift-frontend/package.json index 5dccc12..a9a752b 100644 --- a/flightdrift-frontend/package.json +++ b/flightdrift-frontend/package.json @@ -37,6 +37,7 @@ }, "devDependencies": { "@eslint/js": "^10.0.1", + "@tanstack/eslint-plugin-query": "^5.100.14", "@tanstack/router-cli": "^1.166.42", "@tanstack/router-plugin": "^1.167.34", "@types/node": "^24.12.2", From 3a871e13d756140e55a78a4b0dee1c1b23946086 Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 21:12:06 +0600 Subject: [PATCH 09/19] Enabled approval mode for `getOrganizations` MCP in Codex config. --- .codex/config.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.codex/config.toml b/.codex/config.toml index eb47db0..6a0aa42 100644 --- a/.codex/config.toml +++ b/.codex/config.toml @@ -5,5 +5,8 @@ command = "C:\\Users\\jamius19\\miniconda3\\envs\\awsmcp\\Scripts\\awslabs.opena args = ["--spec-url", "http://localhost:8080/v3/api-docs"] enabled = true +[mcp_servers.flightdrift_openapi.tools.getOrganizations] +approval_mode = "approve" + [sandbox_workspace_write] network_access = true From 3e44c835c35cc41453255bbad79a1e5e9ed55042 Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Fri, 29 May 2026 21:15:09 +0600 Subject: [PATCH 10/19] Removed unused imports and updated UI with logo --- flightdrift-frontend/src/routes/index.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/flightdrift-frontend/src/routes/index.tsx b/flightdrift-frontend/src/routes/index.tsx index 555e484..e5a0363 100644 --- a/flightdrift-frontend/src/routes/index.tsx +++ b/flightdrift-frontend/src/routes/index.tsx @@ -2,18 +2,14 @@ * Author: Jamius Siam * Since: 06/05/2026 */ -import { createFileRoute, Link } from "@tanstack/react-router"; +import { createFileRoute } from "@tanstack/react-router"; import type { JSX } from "react"; -import { Button } from "@/components/ui/button.tsx"; // TODO: Implement a default login page later const Index = (): JSX.Element => { return (
- Flightdrift Login - + Flightdrift Logo
); }; From b86d1f0f6946d42048ad5402063a62a04048a368 Mon Sep 17 00:00:00 2001 From: Jamius Siam Date: Sat, 30 May 2026 00:24:19 +0600 Subject: [PATCH 11/19] Integrated authentication workflow with sign-in and sign-up pages, API client, zustand-based auth store, and schema validations. Added UI components for form handling and alerts. --- .../flightdrift/config/SecurityConfig.java | 12 + flightdrift-frontend/.env | 1 + flightdrift-frontend/AGENTS.md | 5 +- flightdrift-frontend/package-lock.json | 17 +- flightdrift-frontend/package.json | 2 + flightdrift-frontend/src/@types/auth.ts | 36 +++ flightdrift-frontend/src/@types/item.ts | 25 ++ .../src/components/alerts/error-alert.tsx | 24 ++ .../src/components/alerts/success-alert.tsx | 24 ++ .../src/components/{item => items}/boards.tsx | 23 +- .../components/{item => items}/breadcrumb.tsx | 0 .../{item => items}/horizontal-rule.tsx | 0 .../src/components/loader/loader.tsx | 23 ++ .../src/components/sidebar/user-menu.tsx | 48 +++- .../src/components/ui/field.tsx | 34 +++ .../src/components/ui/input.tsx | 24 ++ .../src/components/ui/label.tsx | 23 ++ flightdrift-frontend/src/lib/api-client.ts | 13 ++ flightdrift-frontend/src/lib/auth-api.ts | 40 ++++ flightdrift-frontend/src/lib/auth-schema.ts | 20 ++ flightdrift-frontend/src/lib/env.ts | 11 + flightdrift-frontend/src/lib/form-utils.ts | 25 ++ flightdrift-frontend/src/lib/utils.ts | 24 +- .../src/lib/validation-utils.ts | 7 + flightdrift-frontend/src/main.tsx | 8 +- .../src/routes/auth/index.tsx | 11 + .../src/routes/auth/route.tsx | 96 ++++++++ .../src/routes/auth/signin.tsx | 155 ++++++++++++ .../src/routes/auth/signup.tsx | 220 ++++++++++++++++++ .../src/routes/dash/{item.tsx => items.tsx} | 9 +- .../src/routes/dash/route.tsx | 16 +- flightdrift-frontend/src/routes/index.tsx | 27 ++- flightdrift-frontend/src/stores/auth-store.ts | 57 +++++ flightdrift-frontend/src/vite-env.d.ts | 9 + flightdrift-frontend/tsconfig.app.json | 5 +- flightdrift-frontend/tsconfig.json | 5 +- flightdrift-frontend/vite.config.ts | 1 + 37 files changed, 1017 insertions(+), 63 deletions(-) create mode 100644 flightdrift-frontend/.env create mode 100644 flightdrift-frontend/src/@types/auth.ts create mode 100644 flightdrift-frontend/src/@types/item.ts create mode 100644 flightdrift-frontend/src/components/alerts/error-alert.tsx create mode 100644 flightdrift-frontend/src/components/alerts/success-alert.tsx rename flightdrift-frontend/src/components/{item => items}/boards.tsx (93%) rename flightdrift-frontend/src/components/{item => items}/breadcrumb.tsx (100%) rename flightdrift-frontend/src/components/{item => items}/horizontal-rule.tsx (100%) create mode 100644 flightdrift-frontend/src/components/loader/loader.tsx create mode 100644 flightdrift-frontend/src/components/ui/field.tsx create mode 100644 flightdrift-frontend/src/components/ui/input.tsx create mode 100644 flightdrift-frontend/src/components/ui/label.tsx create mode 100644 flightdrift-frontend/src/lib/api-client.ts create mode 100644 flightdrift-frontend/src/lib/auth-api.ts create mode 100644 flightdrift-frontend/src/lib/auth-schema.ts create mode 100644 flightdrift-frontend/src/lib/env.ts create mode 100644 flightdrift-frontend/src/lib/form-utils.ts create mode 100644 flightdrift-frontend/src/lib/validation-utils.ts create mode 100644 flightdrift-frontend/src/routes/auth/index.tsx create mode 100644 flightdrift-frontend/src/routes/auth/route.tsx create mode 100644 flightdrift-frontend/src/routes/auth/signin.tsx create mode 100644 flightdrift-frontend/src/routes/auth/signup.tsx rename flightdrift-frontend/src/routes/dash/{item.tsx => items.tsx} (82%) create mode 100644 flightdrift-frontend/src/stores/auth-store.ts create mode 100644 flightdrift-frontend/src/vite-env.d.ts diff --git a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/config/SecurityConfig.java b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/config/SecurityConfig.java index 758e24e..974e955 100644 --- a/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/config/SecurityConfig.java +++ b/flightdrift-backend/src/main/java/com/flightdrift/flightdrift/config/SecurityConfig.java @@ -14,6 +14,8 @@ import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /* * Author: Jamius Siam @@ -55,4 +57,14 @@ public PasswordEncoder passwordEncoder() { public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfig) throws Exception { return authConfig.getAuthenticationManager(); } + + @Bean + public WebMvcConfigurer corsConfigurer() { + return new WebMvcConfigurer() { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**").allowedOrigins("*"); + } + }; + } } \ No newline at end of file diff --git a/flightdrift-frontend/.env b/flightdrift-frontend/.env new file mode 100644 index 0000000..a8cf54a --- /dev/null +++ b/flightdrift-frontend/.env @@ -0,0 +1 @@ +VITE_API_BASE_URL=http://localhost:8080 diff --git a/flightdrift-frontend/AGENTS.md b/flightdrift-frontend/AGENTS.md index 4d457de..7eca0f2 100644 --- a/flightdrift-frontend/AGENTS.md +++ b/flightdrift-frontend/AGENTS.md @@ -16,4 +16,7 @@ Here are some rules for the project: 8. Use explicit return types. 9. Don't exceed 120 characters per line, try to keep it to 80. 10. Don't install NPM packages without explicit permission from the user. - 11. Don't run vite or browser to check the visuals for now. \ No newline at end of file + 11. Don't run vite or browser to check the visuals for now. + 12. Move reused types in the `@types` folder. + 13. If people usually use a specific library for a specific task, prompt the user if they want to use it. (e.g., form validation with Zod) + 14. If variables can be moved outside the component, do so. \ No newline at end of file diff --git a/flightdrift-frontend/package-lock.json b/flightdrift-frontend/package-lock.json index 026ee01..66c7d5d 100644 --- a/flightdrift-frontend/package-lock.json +++ b/flightdrift-frontend/package-lock.json @@ -18,6 +18,7 @@ "axios": "^1.16.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "jwt-decode": "^4.0.0", "lucide-react": "^1.17.0", "radix-ui": "^1.4.3", "react": "^19.2.5", @@ -26,6 +27,7 @@ "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.0", "tw-animate-css": "^1.4.0", + "zod": "^4.4.3", "zustand": "^5.0.14" }, "devDependencies": { @@ -6637,6 +6639,15 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -9636,9 +9647,9 @@ } }, "node_modules/zod": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.2.tgz", - "integrity": "sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/flightdrift-frontend/package.json b/flightdrift-frontend/package.json index a9a752b..33c52bc 100644 --- a/flightdrift-frontend/package.json +++ b/flightdrift-frontend/package.json @@ -25,6 +25,7 @@ "axios": "^1.16.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "jwt-decode": "^4.0.0", "lucide-react": "^1.17.0", "radix-ui": "^1.4.3", "react": "^19.2.5", @@ -33,6 +34,7 @@ "tailwind-merge": "^3.6.0", "tailwindcss": "^4.3.0", "tw-animate-css": "^1.4.0", + "zod": "^4.4.3", "zustand": "^5.0.14" }, "devDependencies": { diff --git a/flightdrift-frontend/src/@types/auth.ts b/flightdrift-frontend/src/@types/auth.ts new file mode 100644 index 0000000..ae6fe7a --- /dev/null +++ b/flightdrift-frontend/src/@types/auth.ts @@ -0,0 +1,36 @@ +/* + * Author: Jamius Siam + * Since: 29/05/2026 + */ +export type Account = { + id: string; + name: string; + email: string; + username: string; +}; + +export type ApiResponse = { + success: boolean; + message: string; + data: TData; +}; + +export type SigninRequest = { + username: string; + password: string; +}; + +export type SignupRequest = { + name: string; + email: string; + username: string; + password: string; + invitationCode?: string; +}; + +export type TokenResponse = { + token: string; + userInfo: Account; +}; + +export type SignupResponse = Account; diff --git a/flightdrift-frontend/src/@types/item.ts b/flightdrift-frontend/src/@types/item.ts new file mode 100644 index 0000000..e38e133 --- /dev/null +++ b/flightdrift-frontend/src/@types/item.ts @@ -0,0 +1,25 @@ +/* + * Author: Jamius Siam + * Since: 29/05/2026 + */ +export type BoardItemTag = { + name: string; +}; + +export type BoardItem = { + code: string; + title: string; + assignee: { + name: string; + avatarUrl: string; + }; + status: string; + priority: string; + dateRange: string; + tags: BoardItemTag[]; +}; + +export type Board = { + title: string; + items: BoardItem[]; +}; diff --git a/flightdrift-frontend/src/components/alerts/error-alert.tsx b/flightdrift-frontend/src/components/alerts/error-alert.tsx new file mode 100644 index 0000000..18b6f45 --- /dev/null +++ b/flightdrift-frontend/src/components/alerts/error-alert.tsx @@ -0,0 +1,24 @@ +/* + * Author: Jamius Siam + * Since: 29/05/2026 + */ +import type { JSX } from "react"; + +type ErrorAlertProps = { + message?: string; + show: boolean; +}; + +const ErrorAlert = ({ message, show }: ErrorAlertProps): JSX.Element | null => { + if (!show || !message) { + return null; + } + + return ( +

+ {message} +

+ ); +}; + +export default ErrorAlert; diff --git a/flightdrift-frontend/src/components/alerts/success-alert.tsx b/flightdrift-frontend/src/components/alerts/success-alert.tsx new file mode 100644 index 0000000..d3050da --- /dev/null +++ b/flightdrift-frontend/src/components/alerts/success-alert.tsx @@ -0,0 +1,24 @@ +/* + * Author: Jamius Siam + * Since: 29/05/2026 + */ +import type { JSX } from "react"; + +type SuccessAlertProps = { + message?: string; + show: boolean; +}; + +const SuccessAlert = ({ message, show }: SuccessAlertProps): JSX.Element | null => { + if (!show || !message) { + return null; + } + + return ( +

+ {message} +

+ ); +}; + +export default SuccessAlert; diff --git a/flightdrift-frontend/src/components/item/boards.tsx b/flightdrift-frontend/src/components/items/boards.tsx similarity index 93% rename from flightdrift-frontend/src/components/item/boards.tsx rename to flightdrift-frontend/src/components/items/boards.tsx index 812b6cd..f4f2465 100644 --- a/flightdrift-frontend/src/components/item/boards.tsx +++ b/flightdrift-frontend/src/components/items/boards.tsx @@ -5,28 +5,7 @@ import { Button } from "@/components/ui/button.tsx"; import { CalendarClock, Circle, Minimize2, Plus, Signal, Tag } from "lucide-react"; import type { JSX, ReactNode } from "react"; - -type BoardItemTag = { - name: string; -}; - -type BoardItem = { - code: string; - title: string; - assignee: { - name: string; - avatarUrl: string; - }; - status: string; - priority: string; - dateRange: string; - tags: BoardItemTag[]; -}; - -export type Board = { - title: string; - items: BoardItem[]; -}; +import type { Board, BoardItem } from "@/@types/item.ts"; type BoardsProps = { boards: Board[]; diff --git a/flightdrift-frontend/src/components/item/breadcrumb.tsx b/flightdrift-frontend/src/components/items/breadcrumb.tsx similarity index 100% rename from flightdrift-frontend/src/components/item/breadcrumb.tsx rename to flightdrift-frontend/src/components/items/breadcrumb.tsx diff --git a/flightdrift-frontend/src/components/item/horizontal-rule.tsx b/flightdrift-frontend/src/components/items/horizontal-rule.tsx similarity index 100% rename from flightdrift-frontend/src/components/item/horizontal-rule.tsx rename to flightdrift-frontend/src/components/items/horizontal-rule.tsx diff --git a/flightdrift-frontend/src/components/loader/loader.tsx b/flightdrift-frontend/src/components/loader/loader.tsx new file mode 100644 index 0000000..59e7ac9 --- /dev/null +++ b/flightdrift-frontend/src/components/loader/loader.tsx @@ -0,0 +1,23 @@ +/* + * Author: Jamius Siam + * Since: 29/05/2026 + */ +import { cn } from "@/lib/utils.ts"; +import { LoaderCircle } from "lucide-react"; +import type { JSX } from "react"; + +type LoaderProps = { + className?: string; +}; + +const Loader = ({ className }: LoaderProps): JSX.Element => { + return ( +