Skip to content

feat: Add initial website#73

Open
StoynovAngel wants to merge 24 commits into
mainfrom
feat/add-web-app
Open

feat: Add initial website#73
StoynovAngel wants to merge 24 commits into
mainfrom
feat/add-web-app

Conversation

@StoynovAngel
Copy link
Copy Markdown
Owner

@StoynovAngel StoynovAngel commented May 11, 2026

Summary by CodeRabbit

  • New Features

    • Launched a React web frontend with routing, protected routes, and a home/login flow.
    • Added company management UI: company list, details, create/update DTOs, driver and vehicle lists, and detailed info panels.
    • Built authentication with session handling and guarded pages; global navigation provided.
  • Chores

    • Configured tooling: TypeScript, ESLint, Tailwind/PostCSS, and Vite build setup.
    • Added API client with auth handling and optimized backend read operations.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Warning

Rate limit exceeded

@StoynovAngel has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 28 minutes and 8 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 26894f6a-b5f8-44a2-879d-83c82d143b9e

📥 Commits

Reviewing files that changed from the base of the PR and between 51bb972 and b18a3b4.

📒 Files selected for processing (9)
  • CLAUDE.md
  • backend/src/main/java/com/angel/autonow/DataSeeder.java
  • backend/src/main/resources/application.properties
  • backend/src/main/resources/data.sql
  • web/src/components/company/CompanyList.tsx
  • web/src/components/company/CompanyManagementSidebar.tsx
  • web/src/components/company/DriverList.tsx
  • web/src/hooks/useCompanies.ts
  • web/src/hooks/useDrivers.ts
📝 Walkthrough

Walkthrough

This pull request adds @Transactional(readOnly = true) annotations to four read-only query methods in the backend DriverService and introduces a complete new React web application in the web/ directory with TypeScript, Vite, authentication, API integration, and company/driver/vehicle management UI.

Changes

Backend Transaction Optimization

Layer / File(s) Summary
Read-only Transactional Annotations
backend/src/main/java/com/angel/autonow/driver/DriverService.java
Four query methods (getDriverById, getDriverByLicenseNumber, getAllDrivers, getDriversByCompanyId) are marked with @Transactional(readOnly = true) to optimize transaction handling for read operations.

New React Web Application

Layer / File(s) Summary
Build Configuration and Tooling Setup
web/.gitignore, web/eslint.config.js, web/package.json, web/postcss.config.js, web/tsconfig.app.json, web/tsconfig.json, web/tsconfig.node.json, web/vite.config.ts, frontend/package.json
Package manifests, TypeScript compiler configurations, Vite dev server and build config, ESLint rules, PostCSS Tailwind integration, and gitignore patterns establish the dev environment and build pipeline.
HTML Entry Point and Global Styles
web/index.html, web/src/index.css, web/src/main.tsx
HTML5 shell with root mount point; global Tailwind import, theme color palette, root typography defaults, body reset, and cross-browser scrollbar utilities; React bootstrap in StrictMode.
App Shell with Routing and Providers
web/src/App.tsx, web/src/App.css
App component configures React Query client (refetchOnWindowFocus: false, retry: 1), wraps app in AuthProvider, sets up routes for /login, /home, /companies (protected), and / redirect; App.css defines hero section with 3D transforms, counter, centered layout, navigation, documentation, and decorative elements.
Authentication Context and State
web/src/contexts/AuthContext.tsx
React context manages User object and accessToken state, persists auth data to localStorage on mount and updates, exposes login/logout functions and isAuthenticated computed state, provides useAuth hook that validates context is used within provider.
Authentication UI and Login Flow
web/src/components/auth/..., web/src/pages/Login.tsx
AuthLayout renders centered gradient card container; LoginForm renders controlled email/password inputs with ARIA validation and conditional error alert; ProtectedRoute guards page access and shows loading spinner during auth check; Login page decodes JWT payload in-browser, extracts user claims, calls auth context login, and navigates to /home on success.
Navigation and Page Structure
web/src/components/Navigation.tsx, web/src/pages/Home.tsx
Navigation bar renders route links (Home, Companies) with active-route highlighting and conditionally shows Logout button or Login link based on auth state; Home page displays welcome heading, description, and external documentation links.
API Client and Service Layer
web/src/services/apiClient.ts, web/src/services/company/*.ts, frontend/src/types/company.ts
Axios client configured with local API baseURL and Bearer token injection from localStorage via request interceptor; response interceptor clears auth on 401 and redirects to /login; companyService, driverService, and vehicleService expose REST CRUD methods; frontend types define CreateCompanyDTO and UpdateCompanyDTO.
Data Management Hooks
web/src/hooks/useCompanies.ts, web/src/hooks/useDrivers.ts
useCompanies manages company list retrieval and single company selection with loading/error state; useDrivers manages driver list with optional company filter, selected driver details, and related vehicle loading by driver's vehicleIds array.
Company Information and Selection
web/src/components/company/CompanyInfo.tsx, web/src/components/company/CompanyList.tsx
CompanyInfo renders company card with name, email, phone, address, type badge, and optional description (null state shows prompt); CompanyList renders scrollable selectable company buttons with "Add new company" action.
Driver Information and Selection
web/src/components/company/DriverInfo.tsx, web/src/components/company/DriverList.tsx
DriverInfo renders driver card with availability badge, name, phone, license, and optional image (null state shows prompt); DriverList renders scrollable selectable driver rows with "Add new driver" action.
Vehicle Information Display
web/src/components/company/VehicleInfo.tsx
VehicleInfo renders card with vehicle list showing type, brand, model, image, seat/trunk capacity, air conditioning badge, and ID (empty state when no vehicles).
Management Layout Composition
web/src/components/company/CompanyManagementSidebar.tsx, web/src/components/company/CompanyManagementContent.tsx
CompanyManagementSidebar composes two scrollable lists (companies and drivers) with selection highlighting, counts, conditional empty-state messages, and add buttons; CompanyManagementContent composes CompanyInfo, DriverInfo, and VehicleInfo side-by-side in flex layout.
Company Management Page
web/src/pages/Company.tsx
Company page integrates useCompanies and useDrivers hooks, combines loading/error states, conditionally renders loading spinner or error card, wires CompanyManagementSidebar and CompanyManagementContent with selected IDs and callback handlers for company/driver selection and addition.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • StoynovAngel/AutoNow#71: Both PRs define and export CreateCompanyDTO and UpdateCompanyDTO interfaces in frontend/src/types/company.ts for company payload typing.

🐰 A web app grows in a single bound,
With routes and auth and data sound,
React takes the stage with Vite so fast,
Companies managed at last! ✨🏎️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Add initial website' clearly summarizes the main change—introducing a new web application. It directly addresses the primary objective of the PR (adding a complete website/frontend) and is concise and specific.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-web-app

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/src/main/java/com/angel/autonow/driver/DriverService.java (1)

105-123: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add @Transactional to the deleteDriver method.

The deleteDriver method performs a database write operation (line 121) but lacks a @Transactional annotation. This creates inconsistency with updateDriver (line 61) and risks leaving the operation outside a transaction boundary, which could affect rollback behavior on failure.

🔧 Proposed fix
+@Transactional
 public boolean deleteDriver(Long id, String userEmail) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/java/com/angel/autonow/driver/DriverService.java` around
lines 105 - 123, The deleteDriver method in DriverService performs a DB write
but lacks a `@Transactional` annotation; add `@Transactional` to the deleteDriver
method signature (matching updateDriver) so the deleteRepository.deleteById(id)
call executes within a transaction and will properly roll back on failure,
ensuring consistent transactional boundaries for methods like deleteDriver and
updateDriver in DriverService.
🟡 Minor comments (3)
frontend/package.json-19-19 (1)

19-19: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove @tailwindcss/postcss from frontend dependencies.

Frontend is an Expo/React Native app with no PostCSS build pipeline. This package is a build-time tool only used by web-new (where it correctly belongs in devDependencies with a postcss.config.js). It appears to have been copied from web-new's package.json without proper cleanup and should be removed entirely from frontend.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/package.json` at line 19, The frontend package.json incorrectly
lists the build-time package "@tailwindcss/postcss" as a runtime dependency;
remove the "@tailwindcss/postcss" entry from the dependencies section of
frontend's package.json so it is no longer installed for the Expo/React Native
app (do not move it to devDependencies here — it belongs in web-new). After
removal, run dependency install and confirm no references to
"@tailwindcss/postcss" remain in frontend source or config files.
web-new/src/contexts/AuthContext.tsx-31-36 (1)

31-36: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add error handling for JSON.parse to prevent crashes.

The code calls JSON.parse(storedUser) without a try-catch block. If the stored data is corrupted or invalid JSON, this will throw an uncaught exception and break the app initialization.

🛡️ Proposed fix
 if (storedToken && storedUser) {
-    setAccessToken(storedToken);
-    setUser(JSON.parse(storedUser));
-    axios.defaults.headers.common["Authorization"] = `Bearer ${storedToken}`;
+    try {
+        setAccessToken(storedToken);
+        setUser(JSON.parse(storedUser));
+        axios.defaults.headers.common["Authorization"] = `Bearer ${storedToken}`;
+    } catch (error) {
+        // Clear corrupted data
+        localStorage.removeItem("accessToken");
+        localStorage.removeItem("userInfo");
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/contexts/AuthContext.tsx` around lines 31 - 36, Wrap the
JSON.parse(storedUser) call in a try-catch inside the auth initialization so
corrupted/invalid stored user data doesn't crash the app; on success call
setUser(parsedUser) and setAccessToken(storedToken) and set
axios.defaults.headers.common["Authorization"], and on parse failure clear the
invalid storage (removeItem for the user and token), delete
axios.defaults.headers.common["Authorization"] if set, and proceed to
setIsLoading(false) so initialization continues gracefully. Use the existing
symbols setUser, setAccessToken, storedUser, storedToken, and
axios.defaults.headers.common to locate and update the code.
web-new/src/components/Navigation.tsx-10-16 (1)

10-16: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing route definitions for Drivers, Vehicles, and Orders.

The navigation component includes links to /drivers, /vehicles, and /orders (lines 13-15), but these routes are not defined in web-new/src/App.tsx. Add the corresponding route definitions to prevent users from encountering undefined routes when clicking these links.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/components/Navigation.tsx` around lines 10 - 16, navItems
includes links for '/drivers', '/vehicles', and '/orders' but App.tsx lacks
corresponding routes; add Route entries in your router to prevent
undefined-route navigation. Import the appropriate components (e.g., Drivers,
Vehicles, Orders or DriversPage, VehiclesPage, OrdersPage) into App.tsx and add
Route definitions matching the path strings used in navItems (for example Route
path="/drivers" element={<Drivers/>} etc.), ensuring the component names exactly
match your imports and the router type used (react-router v6 vs v5) in the
existing App component.
🧹 Nitpick comments (9)
web-new/.gitignore (1)

1-24: 💤 Low value

Solid .gitignore foundation for a Vite project.

The file covers all essential patterns: dependencies, build outputs, logs, and editor artifacts. The .vscode exception for extensions.json is a nice touch.

Consider adding these commonly generated directories for completeness:

 node_modules
 dist
 dist-ssr
 *.local
+
+# Vite cache
+.vite
+
+# Test coverage
+coverage
+
+# Environment variables
+.env
+.env.production
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/.gitignore` around lines 1 - 24, Add common generated/cache
directories to the .gitignore to avoid committing build caches and coverage
artifacts: include entries such as coverage/, .cache/, .turbo/, .parcel-cache/,
.vite/, and .eslintcache (and similar cache/build folders your toolchain
creates) so the web-new/.gitignore excludes those directories in addition to the
existing node_modules, dist, logs, and editor artifacts.
web-new/src/components/company/DriverInfo.tsx (1)

1-3: ⚡ Quick win

Define a concrete driver type to restore type safety.

Line 2 uses any, removing compile-time checks on all rendered fields (firstName, lastName, available, phoneNumber, licenseNumber, expertiseType, imageUrl). This invites runtime errors if the shape of the driver object changes.

The code renders phoneNumber, licenseNumber, and expertiseType without null checks, so these should be required properties in the type (not optional). imageUrl is correctly conditionally rendered, making it optional.

Proposed type
 interface DriverInfoProps {
-    driver: any;
+    driver: {
+        firstName: string;
+        lastName: string;
+        available: boolean;
+        phoneNumber: string;
+        licenseNumber: string;
+        expertiseType: string;
+        imageUrl?: string;
+    } | null;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/components/company/DriverInfo.tsx` around lines 1 - 3, Replace
the loose any type on DriverInfoProps with a concrete interface describing the
expected driver shape: update DriverInfoProps to require a driver object
containing string firstName, lastName, phoneNumber, licenseNumber,
expertiseType, a boolean available, and an optional string imageUrl; then update
the component signature that references DriverInfoProps (the driver prop used in
DriverInfo) so TypeScript enforces those fields when rendering firstName,
lastName, available, phoneNumber, licenseNumber, expertiseType and conditionally
rendering imageUrl.
web-new/src/services/apiClient.ts (2)

28-31: ⚡ Quick win

Consider using React Router for navigation instead of hard redirect.

window.location.href = "/login" causes a full page reload, losing React state and disrupting the SPA experience. If React Router is available, use navigate("/login") for smoother client-side navigation.

♻️ Alternative approach using React Router

If you need to preserve the current approach for simplicity, this is acceptable. However, for a better user experience, consider passing a navigation callback:

// In a hook or context that has access to router
const setupApiClient = (navigate: NavigateFunction) => {
    apiClient.interceptors.response.use(
        (response) => response,
        (error) => {
            if (error.response?.status === 401) {
                localStorage.removeItem("accessToken");
                localStorage.removeItem("userInfo");
                navigate("/login", { replace: true });
            }
            return Promise.reject(error);
        }
    );
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/services/apiClient.ts` around lines 28 - 31, The response
interceptor in apiClient currently performs a hard redirect with
window.location.href = "/login", which causes a full page reload; update the
interceptor (apiClient.interceptors.response or the setupApiClient/initApiClient
function where the interceptor is attached) to accept a React Router
NavigateFunction (e.g., pass a navigate callback into the client setup) and call
navigate("/login", { replace: true }) instead of using window.location.href;
remove the direct window.location usage and ensure callers that initialize the
client provide the navigate function (or read it from a router-aware context) so
401 handling uses client-side navigation.

3-3: ⚡ Quick win

Use environment variable for API base URL.

The hardcoded localhost:8080 URL prevents deployment flexibility. Use an environment variable (e.g., import.meta.env.VITE_API_BASE_URL for Vite) to support different environments.

♻️ Proposed fix
-const API_BASE_URL = "http://localhost:8080/api";
+const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "http://localhost:8080/api";

Create a .env file:

VITE_API_BASE_URL=http://localhost:8080/api
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/services/apiClient.ts` at line 3, Replace the hardcoded
API_BASE_URL constant in web-new/src/services/apiClient.ts with an
environment-driven value: read import.meta.env.VITE_API_BASE_URL and fall back
to the existing "http://localhost:8080/api" if the env var is undefined; update
the API_BASE_URL constant initialization so consumers of API_BASE_URL (or
functions in this module) automatically use the environment-configured base URL
at runtime.
web-new/src/components/company/VehicleInfo.tsx (1)

43-45: 💤 Low value

Consider using CSS class toggle instead of inline style manipulation.

While functional, directly manipulating style.display in the event handler couples presentation logic with behavior. Consider toggling a CSS class (e.g., hidden) for better separation of concerns.

♻️ Alternative approach
 <img
     src={vehicle.imageURL}
     alt={`${vehicle.brand} ${vehicle.model}`}
     className="w-full h-full object-cover"
     onError={(e) => {
-        e.currentTarget.style.display = 'none';
+        e.currentTarget.classList.add('hidden');
     }}
 />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/components/company/VehicleInfo.tsx` around lines 43 - 45, Replace
the inline style mutation in the onError handler with a CSS class toggle:
instead of setting e.currentTarget.style.display = 'none' inside the onError
callback in VehicleInfo.tsx, add/remove (or toggle) a semantic class like
"hidden" (e.g., e.currentTarget.classList.add('hidden')) and ensure a
corresponding .hidden { display: none; } rule exists in the component
stylesheet; this keeps presentation in CSS and behavior in JS while still hiding
the failed element.
web-new/src/services/company/vehicleService.ts (1)

14-18: 🏗️ Heavy lift

Consider a batch endpoint to avoid N+1 HTTP requests.

getVehiclesByIds makes a separate HTTP request for each vehicle ID. While Promise.all parallelizes them, this creates significant overhead for large arrays (network round-trips, connection overhead, increased server load).

If feasible, implement a backend batch endpoint (e.g., GET /vehicles?ids=1,2,3) to fetch multiple vehicles in a single request.

💡 Suggested batch endpoint approach

Backend implementation (example):

// Backend: GET /vehicles?ids=1,2,3
`@GetMapping`("/vehicles")
public List<Vehicle> getVehicles(`@RequestParam` List<String> ids) {
    return vehicleRepository.findAllById(ids);
}

Frontend:

-getVehiclesByIds: async (ids: string[]) => {
-    const requests = ids.map(id => apiClient.get(`/vehicles/${id}`));
-    const responses = await Promise.all(requests);
-    return responses.map(response => response.data);
-},
+getVehiclesByIds: async (ids: string[]) => {
+    const {data} = await apiClient.get('/vehicles', {
+        params: { ids: ids.join(',') }
+    });
+    return data;
+},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/services/company/vehicleService.ts` around lines 14 - 18, The
getVehiclesByIds function currently issues N requests via apiClient.get for each
id; change it to call a single batch endpoint (e.g., GET /vehicles?ids=1,2,3) by
building a comma-separated ids query param and calling
apiClient.get('/vehicles', { params: { ids: ids.join(',') } }) (or the backend's
expected param shape), then return response.data (array). Update the function
name getVehiclesByIds and its call sites if necessary to expect an array result;
if the backend does not yet support batching, add a feature-flagged/conditional
path that falls back to the existing apiClient.get(`/vehicles/${id}`)
Promise.all implementation.
web-new/src/hooks/useDrivers.ts (1)

52-60: 💤 Low value

Clarify the need for Array.from conversion.

Line 54 uses Array.from(data.vehicleIds).map(String), which suggests vehicleIds might not be a standard array. If the backend always returns a proper array, this defensive conversion is unnecessary and adds complexity.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/hooks/useDrivers.ts` around lines 52 - 60, The current conversion
Array.from(data.vehicleIds).map(String) in useDrivers.ts is defensive and
unnecessary if data.vehicleIds is always a plain array; update the code in the
block that calls vehicleService.getVehiclesByIds (the code that sets driver
vehicles via setDriverVehicles) to directly map the array with
data.vehicleIds.map(String). If vehicleIds can be a Set or other iterable,
normalize explicitly with [...data.vehicleIds].map(String) and add a short type
guard (Array.isArray(data.vehicleIds) or typeof check) before mapping to avoid
redundant conversions.
web-new/src/hooks/useCompanies.ts (1)

20-28: 💤 Low value

Consider removing console.log statements before production.

The code includes several console.log and console.error statements that are helpful during development but may expose implementation details in production builds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/hooks/useCompanies.ts` around lines 20 - 28, In useCompanies,
remove or replace the development console statements (console.log and
console.error) inside the data fetch try/catch/finally block—specifically the
"Companies fetched:" console.log and the two console.error calls—and instead use
the app's centralized logging or error-reporting mechanism (or only set state
via setCompanies, setError and setLoading) so no raw console output remains in
production; update any references accordingly to use the logger API or silence
the logs before merge.
web-new/src/pages/Company.tsx (1)

27-35: ⚡ Quick win

Avoid dead-end “Add” actions in the UI.

Line 29 and Line 34 only log placeholders, but these callbacks are wired to interactive controls. Please disable/hide those actions until implemented, or route them to a minimal modal/flow so users don’t hit no-op buttons.

If helpful, I can draft a minimal “Coming soon” modal wiring for both actions and keep the current layout intact.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web-new/src/pages/Company.tsx` around lines 27 - 35, The handlers
handleAddCompany and handleAddDriver are currently no-op placeholders wired to
interactive controls; either disable/hide those controls or replace the
console.log with a minimal “Coming soon” modal flow: add a boolean state (e.g.,
isComingSoonOpen and comingSoonType) and a small modal component or reuse the
app's Modal to show a message and Close button, update handleAddCompany and
handleAddDriver to set comingSoonType ('company'|'driver') and open the modal,
and change the buttons to open that modal (or alternatively set their disabled
prop and add a tooltip) so users don't hit dead-end actions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web-new/src/components/auth/AuthLayout.tsx`:
- Around line 1-3: AuthLayoutProps references React.ReactNode but React isn't
imported; import the named type and use it directly to satisfy the TS JSX
config: add "import { ReactNode } from 'react'" at the top and change the prop
type to ReactNode (the interface name AuthLayoutProps identifies where to
update), following the same pattern used in AuthContext.tsx.

In `@web-new/src/components/auth/LoginForm.tsx`:
- Around line 18-43: The login form currently uses placeholder-only inputs and
an unannounced error container; update the JSX in LoginForm to add visible
<label> elements tied to the email and password inputs via id and htmlFor (e.g.,
ids "email" and "password"), keep placeholders but ensure accessibility; add
aria-invalid={Boolean(error for that field)} and aria-describedby when you have
field-specific errors; change the errorMessage container (errorMessage) to
include role="alert" and aria-live="assertive" and give it an id so it can be
referenced by aria-describedby on the form or inputs; keep using formData and
onChange but ensure inputs include the new id attributes so labels and ARIA
references resolve.

In `@web-new/src/components/company/CompanyInfo.tsx`:
- Around line 1-3: Replace the loose any with a concrete Company interface and
use it in CompanyInfoProps: define an interface named Company that lists all
properties the CompanyInfo component reads (for example id, name, logoUrl,
description, address, phone, website, createdAt, etc. — include the exact fields
used in CompanyInfo.tsx), then change CompanyInfoProps to company: Company so
the component and any consumers get proper TypeScript type-checking; update any
imports/exports if needed and ensure optional fields are marked with ? to match
actual usage.

In `@web-new/src/components/company/CompanyList.tsx`:
- Around line 2-5: The component uses loose types (companies: any[]) and a
selectedCompanyId: string which can break when company.id is a number; make ID
types consistent by defining companies as an array of a typed interface (e.g.,
Company { id: string; ... }) or accept both shapes by changing selectedCompanyId
and onSelectCompany to use string | number | null and normalizing company.id
when comparing/issuing callbacks. Update the props (companies,
selectedCompanyId, onSelectCompany) and every comparison like company.id ===
selectedCompanyId to use a normalized form (String(company.id) ===
String(selectedCompanyId)) or ensure company.id is cast to the declared type
before comparing/returning from onSelectCompany.
- Around line 13-21: The clickable company row is a div and not keyboard
accessible; replace that div with a semantic <button> element in CompanyList.tsx
(the element using onSelectCompany, selectedCompanyId and company.id), move the
key to the button, add type="button", keep the existing className to preserve
styles, and add an accessibility state such as aria-pressed={selectedCompanyId
=== company.id} or aria-current to indicate selection; ensure onClick stays on
the button and remove any redundant role/onKey handlers since a native button is
keyboard-accessible.

In `@web-new/src/components/company/CompanyManagementContent.tsx`:
- Around line 5-9: The props for CompanyManagementContent use broad any types;
define concrete TypeScript interfaces (e.g., interface Company { id: string;
name: string; /* add necessary fields */ }, interface Driver { id: string; name:
string; /* ... */ }, interface Vehicle { id: string; vin: string; /* ... */ })
and update CompanyManagementContentProps to use selectedCompany: Company,
selectedDriver: Driver, driverVehicles: Vehicle[]; add or export these
interfaces near the component (or import from shared types), and update any call
sites to satisfy the new types.

In `@web-new/src/components/company/CompanyManagementSidebar.tsx`:
- Around line 1-10: Replace the loose any[] types on the
CompanyManagementSidebarProps with concrete interfaces: add a Company interface
(id: string; name: string; optional companyType?: string) and a Driver interface
(id: string; firstName: string; lastName: string; optional licenseNumber?:
string) and update CompanyManagementSidebarProps to use companies: Company[] and
drivers: Driver[] while keeping the existing selectedCompanyId,
selectedDriverId, onSelectCompany, onSelectDriver, onAddCompany, and onAddDriver
signatures; ensure all usages of CompanyManagementSidebarProps, companies, and
drivers in the CompanyManagementSidebar component and any consumers are updated
to the new types.

In `@web-new/src/components/company/DriverList.tsx`:
- Around line 1-6: Replace the loose any[] by defining a Driver interface and
using it in DriverListProps: create an interface named Driver with typed fields
used by the component (at minimum id: string, firstName: string, lastName:
string, plus other fields the component reads such as email?: string, phone?:
string, status?: string, createdAt?: string), then change
DriverListProps.drivers: any[] to drivers: Driver[] and update any internal
usages that assume driver properties to the typed names (refer to
DriverListProps and the component functions that read driver.id,
driver.firstName, driver.lastName, etc.). Ensure exported/consumed types match
where the prop is constructed or passed.

In `@web-new/src/components/company/VehicleInfo.tsx`:
- Around line 1-3: Define a proper Vehicle interface and use it in
VehicleInfoProps instead of any[]: create a Vehicle interface describing
expected properties used by the component (e.g., id, make, model, year, vin,
mileage, status — mark optional where appropriate), replace
VehicleInfoProps.vehicles: any[] with vehicles: Vehicle[], and update any
internal references in the VehicleInfo component to use the new typed fields for
compile-time checks and IDE autocompletion (ensure imports/exports are adjusted
if the interface is shared).

In `@web-new/src/contexts/AuthContext.tsx`:
- Line 34: The AuthContext currently mutates the global axios defaults by
setting axios.defaults.headers.common["Authorization"] — remove those mutations
(the lines that set axios.defaults.headers.common, e.g., the ones around the
token set/clear points) and instead add a request interceptor to your apiClient
instance (in apiClient.ts) that reads the token (from localStorage or from
AuthContext via a getter) and sets config.headers.Authorization = `Bearer
${token}`; update AuthContext functions that set/clear tokens to persist to
localStorage only and rely on the apiClient interceptor to attach the header.

In `@web-new/src/hooks/useCompanies.ts`:
- Around line 5-9: Introduce a Company interface describing the company shape
(e.g., id: string, name: string, optional fields) and use it in the hook's state
generics: change companies from useState([]) to useState<Company[]>(...) and
selectedCompany from useState(null) to useState<Company | null>(...), keeping
selectedCompanyId as string | null; update any related handlers/assignments
(setCompanies, setSelectedCompany) to respect the Company type so the hook and
its consumers get proper type safety.

In `@web-new/src/hooks/useDrivers.ts`:
- Around line 6-11: Introduce proper TypeScript interfaces and use them for the
hook state: add interfaces Driver and Vehicle (with fields like id, firstName,
lastName, licenseNumber?, vehicleIds?) and replace the loose any/implicit types
on drivers, selectedDriver, and driverVehicles by typing useState as
useState<Driver[]>, useState<Driver | null>, and useState<Vehicle[]>
respectively; update selectedDriverId to remain string | null and ensure setter
functions (setDrivers, setSelectedDriver, setDriverVehicles) and any function
signatures in the hook that read or write these values use the new types so
callers get full type safety.

In `@web-new/src/pages/Login.tsx`:
- Around line 28-54: decodeJWT currently assumes a well-formed JWT and
handleSubmit dereferences decodedToken without checking for null, which can
crash the client on malformed tokens; update decodeJWT to first validate token
format (ensure token.split('.') yields 3 parts) and handle padded/base64
decoding errors, and in handleSubmit check that decodedToken is non-null and
contains required claims (sub and authorities) before constructing userInfo or
persisting the token—if validation fails, surface an error path (reject the
login flow, show an error, and avoid using undefined claims). Use the function
names decodeJWT and handleSubmit and the variables decodedToken and userInfo to
locate and change the code.

In `@web-new/src/services/api.ts`:
- Around line 24-27: The 401 handler unconditionally removes the token and
hard-redirects (localStorage.removeItem and window.location.href) which triggers
reloads for auth endpoints; update the error handling block that checks
error.response?.status === 401 to first inspect error.config?.url (or request
URL) and skip redirect for auth-related endpoints (e.g., paths containing
'/auth', '/login', '/token' or your login API route), only then remove token and
perform a client-side navigation (use your router push or replace) instead of
window.location.href to preserve app state and error context.
- Around line 12-14: The code in api.ts reads and removes the wrong localStorage
key ('token') which breaks authentication; update the localStorage calls in this
file so that localStorage.getItem('token') and the 401 error removal use the
same key as the rest of the app ('accessToken'), i.e., change the
getItem/removeItem references to 'accessToken' and ensure the Authorization
header assignment (config.headers.Authorization = `Bearer ${token}`) uses that
retrieved value; alternatively, remove this api.ts if you intend to rely solely
on apiClient.ts so there are not two conflicting token sources.

In `@web-new/src/services/company/companyService.ts`:
- Line 14: Replace the loose any types for company payloads with explicit
interfaces: define a CreateCompanyPayload and UpdateCompanyPayload (e.g.,
required fields like name, address, contactEmail, optional fields as needed) and
use those types in the service method signatures (replace companyData: any in
createCompany and updateCompany methods). Update any internal references in
createCompany and updateCompany to rely on the typed properties (and add runtime
validation if needed) and export/import the interfaces where consumed so callers
get compile-time checks.

In `@web-new/src/services/company/driverService.ts`:
- Around line 19-26: Define a concrete DriverData type and replace the `any`
usages: create a `DriverData` interface (or import an existing one) listing
required fields like firstName, lastName, licenseNumber and optional fields such
as companyId, then update the `createDriver` and `updateDriver` function
signatures to accept `driverData: DriverData` (and, optionally, tighten return
types to Promise<Driver> or Promise<DriverResponse> if you have a response type)
while leaving the apiClient.post/put calls unchanged; ensure the new type is
exported/imported where needed and adjust any call sites that passed
loosely-typed objects to conform to the new interface.

In `@web-new/src/services/company/vehicleService.ts`:
- Line 20: The createVehicle method currently uses vehicleData: any (and
similarly updateVehicle) which disables type safety; define explicit TypeScript
interfaces (e.g., CreateVehiclePayload and UpdateVehiclePayload) that list
required/optional fields for vehicle creation and updates, import or declare
them in this module, then replace vehicleData: any in createVehicle and the
corresponding parameter in updateVehicle with the new interfaces and update any
internal usages to match the typed properties (adjust helper functions or API
calls to accept the new types).

In `@web-new/vite.config.ts`:
- Line 10: The Vite config uses __dirname in path.resolve('@',
path.resolve(__dirname, './src')) which fails in ESM; fix by either defining
__dirname for ESM at the top of vite.config.ts (import fileURLToPath from 'url'
and set __dirname = path.dirname(fileURLToPath(import.meta.url'))) before using
path.resolve, or simply replace path.resolve(__dirname, './src') with '/src' (or
path.resolve(process.cwd(), 'src')) so the alias '@' points to the project src
directory; update the alias entry where '@' is defined accordingly.

---

Outside diff comments:
In `@backend/src/main/java/com/angel/autonow/driver/DriverService.java`:
- Around line 105-123: The deleteDriver method in DriverService performs a DB
write but lacks a `@Transactional` annotation; add `@Transactional` to the
deleteDriver method signature (matching updateDriver) so the
deleteRepository.deleteById(id) call executes within a transaction and will
properly roll back on failure, ensuring consistent transactional boundaries for
methods like deleteDriver and updateDriver in DriverService.

---

Minor comments:
In `@frontend/package.json`:
- Line 19: The frontend package.json incorrectly lists the build-time package
"@tailwindcss/postcss" as a runtime dependency; remove the
"@tailwindcss/postcss" entry from the dependencies section of frontend's
package.json so it is no longer installed for the Expo/React Native app (do not
move it to devDependencies here — it belongs in web-new). After removal, run
dependency install and confirm no references to "@tailwindcss/postcss" remain in
frontend source or config files.

In `@web-new/src/components/Navigation.tsx`:
- Around line 10-16: navItems includes links for '/drivers', '/vehicles', and
'/orders' but App.tsx lacks corresponding routes; add Route entries in your
router to prevent undefined-route navigation. Import the appropriate components
(e.g., Drivers, Vehicles, Orders or DriversPage, VehiclesPage, OrdersPage) into
App.tsx and add Route definitions matching the path strings used in navItems
(for example Route path="/drivers" element={<Drivers/>} etc.), ensuring the
component names exactly match your imports and the router type used
(react-router v6 vs v5) in the existing App component.

In `@web-new/src/contexts/AuthContext.tsx`:
- Around line 31-36: Wrap the JSON.parse(storedUser) call in a try-catch inside
the auth initialization so corrupted/invalid stored user data doesn't crash the
app; on success call setUser(parsedUser) and setAccessToken(storedToken) and set
axios.defaults.headers.common["Authorization"], and on parse failure clear the
invalid storage (removeItem for the user and token), delete
axios.defaults.headers.common["Authorization"] if set, and proceed to
setIsLoading(false) so initialization continues gracefully. Use the existing
symbols setUser, setAccessToken, storedUser, storedToken, and
axios.defaults.headers.common to locate and update the code.

---

Nitpick comments:
In `@web-new/.gitignore`:
- Around line 1-24: Add common generated/cache directories to the .gitignore to
avoid committing build caches and coverage artifacts: include entries such as
coverage/, .cache/, .turbo/, .parcel-cache/, .vite/, and .eslintcache (and
similar cache/build folders your toolchain creates) so the web-new/.gitignore
excludes those directories in addition to the existing node_modules, dist, logs,
and editor artifacts.

In `@web-new/src/components/company/DriverInfo.tsx`:
- Around line 1-3: Replace the loose any type on DriverInfoProps with a concrete
interface describing the expected driver shape: update DriverInfoProps to
require a driver object containing string firstName, lastName, phoneNumber,
licenseNumber, expertiseType, a boolean available, and an optional string
imageUrl; then update the component signature that references DriverInfoProps
(the driver prop used in DriverInfo) so TypeScript enforces those fields when
rendering firstName, lastName, available, phoneNumber, licenseNumber,
expertiseType and conditionally rendering imageUrl.

In `@web-new/src/components/company/VehicleInfo.tsx`:
- Around line 43-45: Replace the inline style mutation in the onError handler
with a CSS class toggle: instead of setting e.currentTarget.style.display =
'none' inside the onError callback in VehicleInfo.tsx, add/remove (or toggle) a
semantic class like "hidden" (e.g., e.currentTarget.classList.add('hidden')) and
ensure a corresponding .hidden { display: none; } rule exists in the component
stylesheet; this keeps presentation in CSS and behavior in JS while still hiding
the failed element.

In `@web-new/src/hooks/useCompanies.ts`:
- Around line 20-28: In useCompanies, remove or replace the development console
statements (console.log and console.error) inside the data fetch
try/catch/finally block—specifically the "Companies fetched:" console.log and
the two console.error calls—and instead use the app's centralized logging or
error-reporting mechanism (or only set state via setCompanies, setError and
setLoading) so no raw console output remains in production; update any
references accordingly to use the logger API or silence the logs before merge.

In `@web-new/src/hooks/useDrivers.ts`:
- Around line 52-60: The current conversion
Array.from(data.vehicleIds).map(String) in useDrivers.ts is defensive and
unnecessary if data.vehicleIds is always a plain array; update the code in the
block that calls vehicleService.getVehiclesByIds (the code that sets driver
vehicles via setDriverVehicles) to directly map the array with
data.vehicleIds.map(String). If vehicleIds can be a Set or other iterable,
normalize explicitly with [...data.vehicleIds].map(String) and add a short type
guard (Array.isArray(data.vehicleIds) or typeof check) before mapping to avoid
redundant conversions.

In `@web-new/src/pages/Company.tsx`:
- Around line 27-35: The handlers handleAddCompany and handleAddDriver are
currently no-op placeholders wired to interactive controls; either disable/hide
those controls or replace the console.log with a minimal “Coming soon” modal
flow: add a boolean state (e.g., isComingSoonOpen and comingSoonType) and a
small modal component or reuse the app's Modal to show a message and Close
button, update handleAddCompany and handleAddDriver to set comingSoonType
('company'|'driver') and open the modal, and change the buttons to open that
modal (or alternatively set their disabled prop and add a tooltip) so users
don't hit dead-end actions.

In `@web-new/src/services/apiClient.ts`:
- Around line 28-31: The response interceptor in apiClient currently performs a
hard redirect with window.location.href = "/login", which causes a full page
reload; update the interceptor (apiClient.interceptors.response or the
setupApiClient/initApiClient function where the interceptor is attached) to
accept a React Router NavigateFunction (e.g., pass a navigate callback into the
client setup) and call navigate("/login", { replace: true }) instead of using
window.location.href; remove the direct window.location usage and ensure callers
that initialize the client provide the navigate function (or read it from a
router-aware context) so 401 handling uses client-side navigation.
- Line 3: Replace the hardcoded API_BASE_URL constant in
web-new/src/services/apiClient.ts with an environment-driven value: read
import.meta.env.VITE_API_BASE_URL and fall back to the existing
"http://localhost:8080/api" if the env var is undefined; update the API_BASE_URL
constant initialization so consumers of API_BASE_URL (or functions in this
module) automatically use the environment-configured base URL at runtime.

In `@web-new/src/services/company/vehicleService.ts`:
- Around line 14-18: The getVehiclesByIds function currently issues N requests
via apiClient.get for each id; change it to call a single batch endpoint (e.g.,
GET /vehicles?ids=1,2,3) by building a comma-separated ids query param and
calling apiClient.get('/vehicles', { params: { ids: ids.join(',') } }) (or the
backend's expected param shape), then return response.data (array). Update the
function name getVehiclesByIds and its call sites if necessary to expect an
array result; if the backend does not yet support batching, add a
feature-flagged/conditional path that falls back to the existing
apiClient.get(`/vehicles/${id}`) Promise.all implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e9b7008d-50f8-45c1-8663-520b51ee2367

📥 Commits

Reviewing files that changed from the base of the PR and between 6bd16bb and ce5b66e.

⛔ Files ignored due to path filters (7)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • web-new/package-lock.json is excluded by !**/package-lock.json
  • web-new/public/favicon.svg is excluded by !**/*.svg
  • web-new/public/icons.svg is excluded by !**/*.svg
  • web-new/src/assets/hero.png is excluded by !**/*.png
  • web-new/src/assets/react.svg is excluded by !**/*.svg
  • web-new/src/assets/vite.svg is excluded by !**/*.svg
📒 Files selected for processing (38)
  • backend/src/main/java/com/angel/autonow/driver/DriverService.java
  • frontend/package.json
  • frontend/src/types/company.ts
  • web-new/.gitignore
  • web-new/eslint.config.js
  • web-new/index.html
  • web-new/package.json
  • web-new/postcss.config.js
  • web-new/src/App.css
  • web-new/src/App.tsx
  • web-new/src/components/Navigation.tsx
  • web-new/src/components/auth/AuthLayout.tsx
  • web-new/src/components/auth/LoginForm.tsx
  • web-new/src/components/auth/ProtectedRoute.tsx
  • web-new/src/components/company/CompanyInfo.tsx
  • web-new/src/components/company/CompanyList.tsx
  • web-new/src/components/company/CompanyManagementContent.tsx
  • web-new/src/components/company/CompanyManagementSidebar.tsx
  • web-new/src/components/company/DriverInfo.tsx
  • web-new/src/components/company/DriverList.tsx
  • web-new/src/components/company/VehicleInfo.tsx
  • web-new/src/contexts/AuthContext.tsx
  • web-new/src/hooks/useCompanies.ts
  • web-new/src/hooks/useDrivers.ts
  • web-new/src/index.css
  • web-new/src/main.tsx
  • web-new/src/pages/Company.tsx
  • web-new/src/pages/Home.tsx
  • web-new/src/pages/Login.tsx
  • web-new/src/services/api.ts
  • web-new/src/services/apiClient.ts
  • web-new/src/services/company/companyService.ts
  • web-new/src/services/company/driverService.ts
  • web-new/src/services/company/vehicleService.ts
  • web-new/tsconfig.app.json
  • web-new/tsconfig.json
  • web-new/tsconfig.node.json
  • web-new/vite.config.ts

Comment thread web/src/components/auth/AuthLayout.tsx
Comment thread web/src/components/auth/LoginForm.tsx
Comment thread web/src/components/company/CompanyInfo.tsx
Comment thread web-new/src/components/company/CompanyList.tsx Outdated
Comment thread web-new/src/components/company/CompanyList.tsx Outdated
Comment thread web-new/src/services/api.ts Outdated
Comment thread web-new/src/services/company/companyService.ts Outdated
Comment thread web-new/src/services/company/driverService.ts Outdated
Comment thread web-new/src/services/company/vehicleService.ts Outdated
Comment thread web/vite.config.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 15

♻️ Duplicate comments (1)
web/src/pages/Login.tsx (1)

42-67: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate token and authorities before use.

Line 47 accesses data.token without checking if it exists or is a string, and Line 58 uses decodedToken.authorities without verifying it's an array. A malformed API response could crash the login flow.

🛡️ Proposed fix
 const handleSubmit = async (e: FormEvent) => {
     e.preventDefault();

     try {
         const {data} = await apiClient.post("/auth/login", formData);
-        const token = data.token;
+        const token = data?.token;
+        if (typeof token !== "string" || !token) {
+            setErrorMessage("Authentication failed: invalid token received");
+            return;
+        }

         const decodedToken = decodeJWT(token);
         if (!decodedToken || !decodedToken.sub || !decodedToken.authorities) {
             setErrorMessage("Authentication failed: invalid token received");
             return;
         }

         const userInfo = {
             id: decodedToken.sub,
             email: formData.email,
-            authorities: decodedToken.authorities
+            authorities: Array.isArray(decodedToken.authorities) ? decodedToken.authorities : []
         };

         login(userInfo, token);
         navigate("/home");
     } catch (error: any) {
         console.error("Login error", error);
         setErrorMessage(error.response?.data?.message || "Invalid email or password");
     }
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/pages/Login.tsx` around lines 42 - 67, handleSubmit currently assumes
data.token is present and decodedToken.authorities is an array; validate both
before proceeding: after the apiClient.post call check that data && typeof
data.token === "string" and return/setErrorMessage if not, then call
decodeJWT(token) and verify decodedToken && typeof decodedToken.sub === "string"
and Array.isArray(decodedToken.authorities) (or coerce to an empty array) before
building userInfo; reference the handleSubmit function, the data.token variable,
and decodedToken.authorities/decodedToken.sub when adding these guards and early
error returns so malformed responses cannot crash the login flow.
🧹 Nitpick comments (4)
web/package.json (1)

27-27: ⚡ Quick win

Remove redundant autoprefixer dependency.

Tailwind CSS v4 includes Lightning CSS which handles vendor prefixes automatically. The autoprefixer package is no longer needed and can be removed to reduce dependencies.

♻️ Proposed fix

Remove from package.json:

     "@types/react-dom": "^19.2.3",
     "@vitejs/plugin-react": "^6.0.1",
-    "autoprefixer": "^10.5.0",
     "eslint": "^10.3.0",

Also remove from web/postcss.config.js:

 export default {
   plugins: {
     '@tailwindcss/postcss': {},
-    autoprefixer: {},
   },
 }

As per coding guidelines, Tailwind CSS v4 documentation states: "Built-in Lightning CSS integration handles vendor prefixes, nesting, minification, and imports automatically. No need for separate PostCSS plugins like autoprefixer or postcss-import."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/package.json` at line 27, The project includes a redundant autoprefixer
dependency ("autoprefixer" in package.json) and a corresponding PostCSS config;
remove the "autoprefixer" entry from package.json and delete its usage from
web/postcss.config.js (remove any autoprefixer import/require and any reference
in the plugins array) because Tailwind v4's Lightning CSS handles vendor
prefixes automatically.
web/src/components/company/VehicleInfo.tsx (1)

49-60: ⚡ Quick win

Prefer React state over direct DOM manipulation for image error handling.

The onError handler directly mutates the DOM via style.display, which bypasses React's reconciliation and can lead to state inconsistencies or stale closures.

⚛️ Proposed refactor using React state

Update the component to track image load errors in state:

+import { useState } from 'react';
+
 const VehicleInfo = ({vehicles}: VehicleInfoProps) => {
+    const [failedImages, setFailedImages] = useState<Set<number>>(new Set());
+
     if (!vehicles || vehicles.length === 0) {
         return (
             // ... empty state
         );
     }

     return (
         <div className="w-72 bg-white rounded-xl shadow-md p-4 border border-gray-100 flex flex-col">
             {/* ... */}
             <div className="flex-1 space-y-3 overflow-y-auto scrollbar-hide">
                 {vehicles.map((vehicle, index) => (
                     <div key={vehicle.id} /* ... */>
-                        {vehicle.imageURL && (
+                        {vehicle.imageURL && !failedImages.has(vehicle.id) && (
                             <div className="w-full h-32 overflow-hidden bg-white/10">
                                 <img
                                     src={vehicle.imageURL}
                                     alt={`${vehicle.brand} ${vehicle.model}`}
                                     className="w-full h-full object-cover"
-                                    onError={(e) => {
-                                        e.currentTarget.style.display = 'none';
-                                    }}
+                                    onError={() => {
+                                        setFailedImages(prev => new Set(prev).add(vehicle.id));
+                                    }}
                                 />
                             </div>
                         )}
                         {/* ... */}
                     </div>
                 ))}
             </div>
         </div>
     );
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/company/VehicleInfo.tsx` around lines 49 - 60, The onError
handler in the VehicleInfo component directly mutates the DOM
(e.currentTarget.style.display) instead of using React state; replace this with
a React state flag (e.g. const [imageError, setImageError] = useState(false))
and update the render to show the <img> only when vehicle.imageURL exists and
imageError is false, change the onError to call setImageError(true), and add a
useEffect to reset imageError when vehicle.imageURL changes; remove the direct
DOM style mutation and rely on the state flag to hide the image.
web/src/components/auth/LoginForm.tsx (2)

29-42: ⚡ Quick win

Add autoComplete attribute for better UX.

The email input is missing autoComplete="email", which helps browsers offer saved credentials and improves the login experience.

📝 Proposed addition
 <input
     id="email"
     type="email"
     placeholder="Email"
     name="email"
+    autoComplete="email"
     value={formData.email}
     onChange={onChange}
     aria-invalid={Boolean(errorMessage)}
     aria-describedby={errorMessage ? "login-error" : undefined}
     className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-violet-500"
 />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/auth/LoginForm.tsx` around lines 29 - 42, The email input
in LoginForm is missing an autoComplete attribute; update the input element with
id="email" (the one using value={formData.email}, onChange={onChange},
aria-invalid={Boolean(errorMessage)}) to include autoComplete="email" so
browsers can offer saved credentials and improve UX.

44-57: ⚡ Quick win

Add autoComplete attribute for better UX.

The password input is missing autoComplete="current-password", which helps browsers offer saved credentials.

📝 Proposed addition
 <input
     id="password"
     type="password"
     placeholder="Password"
     name="password"
+    autoComplete="current-password"
     value={formData.password}
     onChange={onChange}
     aria-invalid={Boolean(errorMessage)}
     aria-describedby={errorMessage ? "login-error" : undefined}
     className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-violet-500"
 />
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/auth/LoginForm.tsx` around lines 44 - 57, The password
input in the LoginForm component is missing an autoComplete attribute; update
the <input> for id="password" (in LoginForm.tsx) to include
autoComplete="current-password" so browsers can offer saved credentials—locate
the input that uses name="password", value={formData.password}, and
onChange={onChange} and add the attribute there.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/src/App.css`:
- Around line 1-184: The stylesheet uses undefined CSS custom properties
(--accent, --accent-bg, --accent-border, --border, --text-h, --social-bg,
--shadow) referenced by selectors like .counter, .hero (framework, vite),
`#next-steps`, `#docs` and .ticks; add those variables to your global :root (main
index.css) with sensible color and shadow values (e.g., accent color, accent
background, accent border color, border color, heading text color, social button
background, and a box-shadow variable) so those selectors resolve correctly and
visuals render consistently.

In `@web/src/components/company/CompanyList.tsx`:
- Around line 3-8: The prop types are mismatched: Company.id is a number but
CompanyListProps.selectedCompanyId is typed string | null, which causes runtime
String() conversions; change selectedCompanyId to number | null and update the
onSelectCompany signature to (companyId: number) => void (and any callers) so
comparisons in CompanyList (where String(...) was used) can directly compare
numeric ids (remove String(...) conversions and adjust equality checks
accordingly); ensure any map keys or element ids that require strings call
.toString() only at render boundaries.

In `@web/src/components/company/DriverList.tsx`:
- Around line 15-26: Replace the non-semantic clickable <div> inside
DriverList.tsx with a <button type="button"> to restore keyboard and
screen-reader accessibility; keep the same className and onClick handler
(onSelectDriver(String(driver.id))) and use aria-pressed={selectedDriverId ===
String(driver.id)} (or aria-current) to communicate selection state for
assistive tech while still rendering driver.firstName and driver.lastName and
preserving the selectedDriverId-based styling logic.

In `@web/src/components/company/VehicleInfo.tsx`:
- Around line 115-122: The JSX in VehicleInfo.tsx uses a truthy check
"{vehicle.companyId && ...}" which will hide the Company ID when companyId ===
0; update the rendering to either remove the conditional entirely (if companyId
is always present) or change it to an explicit null/undefined check (e.g.,
"vehicle.companyId != null") so a valid 0 is displayed; refer to the Company ID
JSX block that uses the "vehicle" variable inside the VehicleInfo component to
locate and fix this.

In `@web/src/components/Navigation.tsx`:
- Around line 23-40: The navigation uses non-semantic elements and multiple <h1>
headings: replace the outer div with a <nav> element and change the navigation
item headings inside the navItems map (the <h1> currently rendered within Link)
to non-heading inline elements (e.g., <span> or plain text) so you don’t produce
multiple <h1>s; update the same change for the "Login" link branch as well,
preserving the existing classes/logic that reference currentPage and item.path
so Link, navItems, and currentPage behavior remain unchanged.

In `@web/src/contexts/AuthContext.tsx`:
- Around line 26-35: The useEffect reads storedUser from localStorage and calls
JSON.parse without guarding against malformed JSON, which can crash
initialization; wrap the JSON.parse of storedUser in a try/catch inside the
useEffect (when storedToken && storedUser) and on parse success call
setUser(parsed), otherwise handle the error by clearing the invalid localStorage
entry (or logging) and continue initializing (still call setIsLoading(false));
update references to storedUser/ setUser/ useEffect to perform this safe-parse
behavior so corrupted data doesn't break the app.

In `@web/src/hooks/useCompanies.ts`:
- Around line 21-26: In the useCompanies hook, remove the development console
statements (console.log('Companies fetched:', data) and console.error('Failed to
fetch companies' / 'Error response:')) and either replace them with the app
logger or drop them entirely; update the catch signature from err: any to err:
unknown and narrow it before accessing properties (e.g., use type guards or
extract error message safely when setting setError), and make the same changes
for the additional occurrence around lines 37-41 in this file (the other
console.error calls that log err.response?.data).
- Around line 32-46: selectCompany has a race condition and doesn't surface
errors or clear stale UI; change its signature to accept companyId: string |
null, update a useRef (e.g., selectedCompanyIdRef) whenever setSelectedCompanyId
is called, and when initiating the async fetch in selectCompany compare the
resolved company id against selectedCompanyIdRef.current before calling
setSelectedCompany so out-of-order responses are ignored; on start of a fetch
clear selectedCompany (or set to null) and set an error state on catch (instead
of only console.error) so the UI can display failures; optionally implement
AbortController to cancel previous requests for extra robustness.

In `@web/src/hooks/useDrivers.ts`:
- Line 29: In the useDrivers hook remove all development console output
(console.log('Drivers fetched:', ...), console.log('Driver details:', ...),
console.log('Driver vehicles:', ...), and console.error('Error response:', ...))
— either drop them or route through your app logger — and update the error
handler signatures to use err: unknown instead of err: any, narrowing/inspecting
the error safely (e.g., check for AxiosError or err && (err as Error).message)
before logging or handling; target the functions/handlers inside useDrivers (the
fetch success and catch blocks) when applying these changes.
- Around line 15-44: fetchDrivers is vulnerable to stale-response races when
companyId changes quickly; update the effect and fetchDrivers to cancel or
ignore outdated requests by using an AbortController (or an "ignore" flag) tied
to each effect run: create an AbortController inside the useEffect before
calling fetchDrivers (or pass it into fetchDrivers), wire the driverService
calls to respect the controller (or check the ignore flag after await), and on
cleanup call controller.abort() (or flip ignore=true) so only the latest
response calls setDrivers, setSelectedDriverId, setSelectedDriver and
setDriverVehicles; also ensure fetchDrivers is memoized (useCallback) or
declared inside the effect to satisfy react-hooks/exhaustive-deps.
- Around line 54-57: In useDrivers.ts replace the unnecessary Array.from call
when converting vehicleIds: inside the block that checks data.vehicleIds (the
expression using data.vehicleIds && data.vehicleIds.length > 0) pass
data.vehicleIds.map(String) directly into vehicleService.getVehiclesByIds
instead of Array.from(data.vehicleIds).map(String); update the call site where
vehicleService.getVehiclesByIds(...) is invoked to use
data.vehicleIds.map(String).

In `@web/src/pages/Login.tsx`:
- Around line 28-40: The decodeJWT function may call atob() on a base64url
payload without proper padding; update decodeJWT to, after replacing '-'/'_'
with '+'/'/', compute padding = (4 - (base64.length % 4)) % 4 and append that
many '=' characters to the base64 string before calling atob, so the payload
length is a multiple of 4 and decoding won't fail in some browsers.

In `@web/src/services/apiClient.ts`:
- Around line 3-10: Replace the hardcoded API_BASE_URL with a value read from
the environment (VITE_API_BASE_URL) when creating the axios instance
(apiClient); use a sensible fallback (e.g., "http://localhost:8080/api") if the
env var is missing, and keep the existing headers and baseURL assignment in
axios.create so the client behaves the same across dev/staging/production
environments. Ensure your .env files define VITE_API_BASE_URL for each
environment.

In `@web/src/services/company/vehicleService.ts`:
- Line 6: The VehiclePayload image field is named imageURL which is inconsistent
with frontend casing (imageUrl) and risks the backend ignoring it; rename the
property in the VehiclePayload type and any uses in vehicleService.ts from
imageURL to imageUrl (or map imageURL -> imageUrl when constructing the request
body) so the outgoing payload uses imageUrl consistently; update references in
functions that construct or send the payload (e.g., any create/update vehicle
methods in vehicleService) to use the new property name to preserve the API
contract.

---

Duplicate comments:
In `@web/src/pages/Login.tsx`:
- Around line 42-67: handleSubmit currently assumes data.token is present and
decodedToken.authorities is an array; validate both before proceeding: after the
apiClient.post call check that data && typeof data.token === "string" and
return/setErrorMessage if not, then call decodeJWT(token) and verify
decodedToken && typeof decodedToken.sub === "string" and
Array.isArray(decodedToken.authorities) (or coerce to an empty array) before
building userInfo; reference the handleSubmit function, the data.token variable,
and decodedToken.authorities/decodedToken.sub when adding these guards and early
error returns so malformed responses cannot crash the login flow.

---

Nitpick comments:
In `@web/package.json`:
- Line 27: The project includes a redundant autoprefixer dependency
("autoprefixer" in package.json) and a corresponding PostCSS config; remove the
"autoprefixer" entry from package.json and delete its usage from
web/postcss.config.js (remove any autoprefixer import/require and any reference
in the plugins array) because Tailwind v4's Lightning CSS handles vendor
prefixes automatically.

In `@web/src/components/auth/LoginForm.tsx`:
- Around line 29-42: The email input in LoginForm is missing an autoComplete
attribute; update the input element with id="email" (the one using
value={formData.email}, onChange={onChange},
aria-invalid={Boolean(errorMessage)}) to include autoComplete="email" so
browsers can offer saved credentials and improve UX.
- Around line 44-57: The password input in the LoginForm component is missing an
autoComplete attribute; update the <input> for id="password" (in LoginForm.tsx)
to include autoComplete="current-password" so browsers can offer saved
credentials—locate the input that uses name="password",
value={formData.password}, and onChange={onChange} and add the attribute there.

In `@web/src/components/company/VehicleInfo.tsx`:
- Around line 49-60: The onError handler in the VehicleInfo component directly
mutates the DOM (e.currentTarget.style.display) instead of using React state;
replace this with a React state flag (e.g. const [imageError, setImageError] =
useState(false)) and update the render to show the <img> only when
vehicle.imageURL exists and imageError is false, change the onError to call
setImageError(true), and add a useEffect to reset imageError when
vehicle.imageURL changes; remove the direct DOM style mutation and rely on the
state flag to hide the image.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 78cfe8f1-36ac-4ad2-8fa2-4cac74b9d338

📥 Commits

Reviewing files that changed from the base of the PR and between ce5b66e and 4f2301f.

⛔ Files ignored due to path filters (6)
  • web/package-lock.json is excluded by !**/package-lock.json
  • web/public/favicon.svg is excluded by !**/*.svg
  • web/public/icons.svg is excluded by !**/*.svg
  • web/src/assets/hero.png is excluded by !**/*.png
  • web/src/assets/react.svg is excluded by !**/*.svg
  • web/src/assets/vite.svg is excluded by !**/*.svg
📒 Files selected for processing (34)
  • web/.gitignore
  • web/eslint.config.js
  • web/index.html
  • web/package.json
  • web/postcss.config.js
  • web/src/App.css
  • web/src/App.tsx
  • web/src/components/Navigation.tsx
  • web/src/components/auth/AuthLayout.tsx
  • web/src/components/auth/LoginForm.tsx
  • web/src/components/auth/ProtectedRoute.tsx
  • web/src/components/company/CompanyInfo.tsx
  • web/src/components/company/CompanyList.tsx
  • web/src/components/company/CompanyManagementContent.tsx
  • web/src/components/company/CompanyManagementSidebar.tsx
  • web/src/components/company/DriverInfo.tsx
  • web/src/components/company/DriverList.tsx
  • web/src/components/company/VehicleInfo.tsx
  • web/src/contexts/AuthContext.tsx
  • web/src/hooks/useCompanies.ts
  • web/src/hooks/useDrivers.ts
  • web/src/index.css
  • web/src/main.tsx
  • web/src/pages/Company.tsx
  • web/src/pages/Home.tsx
  • web/src/pages/Login.tsx
  • web/src/services/apiClient.ts
  • web/src/services/company/companyService.ts
  • web/src/services/company/driverService.ts
  • web/src/services/company/vehicleService.ts
  • web/tsconfig.app.json
  • web/tsconfig.json
  • web/tsconfig.node.json
  • web/vite.config.ts
✅ Files skipped from review due to trivial changes (8)
  • web/tsconfig.json
  • web/index.html
  • web/eslint.config.js
  • web/src/main.tsx
  • web/src/components/auth/AuthLayout.tsx
  • web/.gitignore
  • web/src/components/company/CompanyInfo.tsx
  • web/vite.config.ts

Comment thread web/src/App.css
Comment thread web/src/components/company/CompanyList.tsx
Comment on lines +15 to +26
<div
key={driver.id}
onClick={() => onSelectDriver(String(driver.id))}
className={`px-3 py-2 border rounded-lg cursor-pointer transition ${
selectedDriverId === String(driver.id)
? "bg-violet-100 border-violet-500"
: "bg-white border-gray-300 hover:bg-gray-50"
}`}
>
{driver.firstName} {driver.lastName}
</div>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace div with button element for accessibility.

Using a <div> with onClick for interactive elements creates accessibility barriers. Users navigating with keyboards cannot focus or activate these elements, and screen readers won't announce them as interactive.

♿ Proposed fix to use semantic button
-                    <div
+                    <button
                         key={driver.id}
+                        type="button"
                         onClick={() => onSelectDriver(String(driver.id))}
+                        aria-pressed={selectedDriverId === String(driver.id)}
                         className={`px-3 py-2 border rounded-lg cursor-pointer transition ${
                             selectedDriverId === String(driver.id)
                                 ? "bg-violet-100 border-violet-500"
                                 : "bg-white border-gray-300 hover:bg-gray-50"
                         }`}
                     >
                         {driver.firstName} {driver.lastName}
-                    </div>
+                    </button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div
key={driver.id}
onClick={() => onSelectDriver(String(driver.id))}
className={`px-3 py-2 border rounded-lg cursor-pointer transition ${
selectedDriverId === String(driver.id)
? "bg-violet-100 border-violet-500"
: "bg-white border-gray-300 hover:bg-gray-50"
}`}
>
{driver.firstName} {driver.lastName}
</div>
))}
<button
key={driver.id}
type="button"
onClick={() => onSelectDriver(String(driver.id))}
aria-pressed={selectedDriverId === String(driver.id)}
className={`px-3 py-2 border rounded-lg cursor-pointer transition ${
selectedDriverId === String(driver.id)
? "bg-violet-100 border-violet-500"
: "bg-white border-gray-300 hover:bg-gray-50"
}`}
>
{driver.firstName} {driver.lastName}
</button>
))}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/company/DriverList.tsx` around lines 15 - 26, Replace the
non-semantic clickable <div> inside DriverList.tsx with a <button type="button">
to restore keyboard and screen-reader accessibility; keep the same className and
onClick handler (onSelectDriver(String(driver.id))) and use
aria-pressed={selectedDriverId === String(driver.id)} (or aria-current) to
communicate selection state for assistive tech while still rendering
driver.firstName and driver.lastName and preserving the selectedDriverId-based
styling logic.

Comment on lines +115 to +122
{vehicle.companyId && (
<div className="flex items-center bg-white/15 backdrop-blur-sm p-2 rounded-lg">
<svg className="w-3.5 h-3.5 mr-1.5 text-green-100" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
<span className="font-semibold text-xs">Company ID: {vehicle.companyId}</span>
</div>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove redundant companyId check or handle zero explicitly.

vehicle.companyId is a required number field (not optional), but the conditional {vehicle.companyId && ...} will hide this section if companyId is 0 (since 0 is falsy in JavaScript).

If company ID 0 is a valid value, this is a bug. If not, the check is redundant since the field is always present.

🔧 Proposed fix

Either remove the check entirely (if companyId is always valid):

-                                {vehicle.companyId && (
                                     <div className="flex items-center bg-white/15 backdrop-blur-sm p-2 rounded-lg">
                                         <svg className="w-3.5 h-3.5 mr-1.5 text-green-100" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                                             <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
                                         </svg>
                                         <span className="font-semibold text-xs">Company ID: {vehicle.companyId}</span>
                                     </div>
-                                )}

Or check for undefined/null explicitly if 0 is valid:

-                                {vehicle.companyId && (
+                                {vehicle.companyId != null && (
                                     <div className="flex items-center bg-white/15 backdrop-blur-sm p-2 rounded-lg">
                                         {/* ... */}
                                     </div>
                                 )}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{vehicle.companyId && (
<div className="flex items-center bg-white/15 backdrop-blur-sm p-2 rounded-lg">
<svg className="w-3.5 h-3.5 mr-1.5 text-green-100" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
<span className="font-semibold text-xs">Company ID: {vehicle.companyId}</span>
</div>
)}
{vehicle.companyId != null && (
<div className="flex items-center bg-white/15 backdrop-blur-sm p-2 rounded-lg">
<svg className="w-3.5 h-3.5 mr-1.5 text-green-100" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
<span className="font-semibold text-xs">Company ID: {vehicle.companyId}</span>
</div>
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/company/VehicleInfo.tsx` around lines 115 - 122, The JSX
in VehicleInfo.tsx uses a truthy check "{vehicle.companyId && ...}" which will
hide the Company ID when companyId === 0; update the rendering to either remove
the conditional entirely (if companyId is always present) or change it to an
explicit null/undefined check (e.g., "vehicle.companyId != null") so a valid 0
is displayed; refer to the Company ID JSX block that uses the "vehicle" variable
inside the VehicleInfo component to locate and fix this.

Comment on lines +23 to +40
return (
<div className="fixed top-0 left-0 right-0 z-50 flex items-center justify-center pt-6">
<div className="flex items-center bg-gray-300 opacity-95 rounded-full py-3 px-2 shadow-lg">
{navItems.map((item) => (
<div key={item.path} className="mx-2 sm:mx-3">
<Link to={item.path}>
<h1
className={`btn ${
currentPage === item.path
? "bg-white text-black"
: "bg-transparent text-black"
} border-none text-base sm:text-xl px-6 py-3 cursor-pointer hover:bg-white font-semibold rounded-full shadow-none`}
>
{item.label}
</h1>
</Link>
</div>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use semantic HTML for navigation items.

Lines 29-37 and 53-61 use <h1> elements inside <Link> for navigation items. Multiple <h1> tags violate heading hierarchy and confuse screen readers. The outer container should be a <nav> element, and navigation items should use plain text or <span> instead of headings.

♿ Proposed fix
-    <div className="fixed top-0 left-0 right-0 z-50 flex items-center justify-center pt-6">
+    <nav className="fixed top-0 left-0 right-0 z-50 flex items-center justify-center pt-6">
         <div className="flex items-center bg-gray-300 opacity-95 rounded-full py-3 px-2 shadow-lg">
             {navItems.map((item) => (
                 <div key={item.path} className="mx-2 sm:mx-3">
                     <Link to={item.path}>
-                        <h1
+                        <span
                             className={`btn ${
                                 currentPage === item.path
                                     ? "bg-white text-black"
                                     : "bg-transparent text-black"
                             } border-none text-base sm:text-xl px-6 py-3 cursor-pointer hover:bg-white font-semibold rounded-full shadow-none`}
                         >
                             {item.label}
-                        </h1>
+                        </span>
                     </Link>
                 </div>
             ))}

Apply the same change to the "Login" link (lines 53-61).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<div className="fixed top-0 left-0 right-0 z-50 flex items-center justify-center pt-6">
<div className="flex items-center bg-gray-300 opacity-95 rounded-full py-3 px-2 shadow-lg">
{navItems.map((item) => (
<div key={item.path} className="mx-2 sm:mx-3">
<Link to={item.path}>
<h1
className={`btn ${
currentPage === item.path
? "bg-white text-black"
: "bg-transparent text-black"
} border-none text-base sm:text-xl px-6 py-3 cursor-pointer hover:bg-white font-semibold rounded-full shadow-none`}
>
{item.label}
</h1>
</Link>
</div>
))}
return (
<nav className="fixed top-0 left-0 right-0 z-50 flex items-center justify-center pt-6">
<div className="flex items-center bg-gray-300 opacity-95 rounded-full py-3 px-2 shadow-lg">
{navItems.map((item) => (
<div key={item.path} className="mx-2 sm:mx-3">
<Link to={item.path}>
<span
className={`btn ${
currentPage === item.path
? "bg-white text-black"
: "bg-transparent text-black"
} border-none text-base sm:text-xl px-6 py-3 cursor-pointer hover:bg-white font-semibold rounded-full shadow-none`}
>
{item.label}
</span>
</Link>
</div>
))}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/components/Navigation.tsx` around lines 23 - 40, The navigation uses
non-semantic elements and multiple <h1> headings: replace the outer div with a
<nav> element and change the navigation item headings inside the navItems map
(the <h1> currently rendered within Link) to non-heading inline elements (e.g.,
<span> or plain text) so you don’t produce multiple <h1>s; update the same
change for the "Login" link branch as well, preserving the existing
classes/logic that reference currentPage and item.path so Link, navItems, and
currentPage behavior remain unchanged.

Comment thread web/src/hooks/useDrivers.ts Outdated
Comment on lines +46 to +72
const selectDriver = async (driverId: string) => {
setSelectedDriverId(driverId);
if (driverId) {
try {
const data = await driverService.getDriverById(driverId);
console.log('Driver details:', data);
setSelectedDriver(data);

if (data.vehicleIds && data.vehicleIds.length > 0) {
const vehicleData = await vehicleService.getVehiclesByIds(
Array.from(data.vehicleIds).map(String)
);
console.log('Driver vehicles:', vehicleData);
setDriverVehicles(vehicleData);
} else {
setDriverVehicles([]);
}
} catch (err: any) {
console.error('Failed to fetch driver details', err);
console.error('Error response:', err.response?.data);
setDriverVehicles([]);
}
} else {
setSelectedDriver(null);
setDriverVehicles([]);
}
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

selectDriver swallows errors and is also susceptible to out-of-order responses.

Two concerns:

  1. On failure, neither error state nor a user-visible signal is set — only console output. The previously selected driver/vehicles remain on screen, giving the impression the selection succeeded.
  2. Rapid clicks across drivers can interleave the driver-detail and vehicle fetches; a late response from a prior selection can overwrite the current selectedDriver/driverVehicles.
  3. Loading is not set while detail+vehicle fetches are in flight, so the UI has no way to render a skeleton/spinner during selection.

Recommend (a) tracking the latest requested id via a ref or AbortController, (b) setting error (or a dedicated selectionError) in catch, and (c) toggling a loading flag for the selection lifecycle.

Also the parameter is typed driverId: string but if (driverId) branches on falsy — change the type to string | null to match the contract.

Comment on lines +54 to +57
if (data.vehicleIds && data.vehicleIds.length > 0) {
const vehicleData = await vehicleService.getVehiclesByIds(
Array.from(data.vehicleIds).map(String)
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect Driver type and driverService return shape
fd -e ts -e tsx | xargs rg -nP -C2 '\bvehicleIds\b'
fd 'DriverInfo\.(ts|tsx)$' --exec cat
fd 'driverService\.(ts|tsx)$' --exec cat

Repository: StoynovAngel/AutoNow

Length of output: 7003


🏁 Script executed:

cat -n web/src/hooks/useDrivers.ts | head -80

Repository: StoynovAngel/AutoNow

Length of output: 3650


Remove unnecessary Array.from() call.

vehicleIds is declared as number[] in the Driver interface, so Array.from() is redundant. Use data.vehicleIds.map(String) directly instead of Array.from(data.vehicleIds).map(String).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/hooks/useDrivers.ts` around lines 54 - 57, In useDrivers.ts replace
the unnecessary Array.from call when converting vehicleIds: inside the block
that checks data.vehicleIds (the expression using data.vehicleIds &&
data.vehicleIds.length > 0) pass data.vehicleIds.map(String) directly into
vehicleService.getVehiclesByIds instead of
Array.from(data.vehicleIds).map(String); update the call site where
vehicleService.getVehiclesByIds(...) is invoked to use
data.vehicleIds.map(String).

Comment thread web/src/pages/Login.tsx
Comment on lines +28 to +40
const decodeJWT = (token: string) => {
try {
const parts = token.split('.');
if (parts.length !== 3) return null;
const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map((c) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
} catch {
return null;
}
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add base64 padding before decoding JWT.

Line 32 uses atob() without ensuring the base64 string is properly padded. JWT payloads use base64url encoding, which omits padding. atob() can fail in some browsers when the input length is not a multiple of 4.

🔧 Proposed fix
 const decodeJWT = (token: string) => {
     try {
         const parts = token.split('.');
         if (parts.length !== 3) return null;
-        const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
+        const base64url = parts[1];
+        const base64 = base64url
+            .replace(/-/g, '+')
+            .replace(/_/g, '/')
+            .padEnd(base64url.length + ((4 - (base64url.length % 4)) % 4), '=');
         const jsonPayload = decodeURIComponent(atob(base64).split('').map((c) => {
             return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
         }).join(''));
         return JSON.parse(jsonPayload);
     } catch {
         return null;
     }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const decodeJWT = (token: string) => {
try {
const parts = token.split('.');
if (parts.length !== 3) return null;
const base64 = parts[1].replace(/-/g, '+').replace(/_/g, '/');
const jsonPayload = decodeURIComponent(atob(base64).split('').map((c) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
} catch {
return null;
}
};
const decodeJWT = (token: string) => {
try {
const parts = token.split('.');
if (parts.length !== 3) return null;
const base64url = parts[1];
const base64 = base64url
.replace(/-/g, '+')
.replace(/_/g, '/')
.padEnd(base64url.length + ((4 - (base64url.length % 4)) % 4), '=');
const jsonPayload = decodeURIComponent(atob(base64).split('').map((c) => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
} catch {
return null;
}
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/pages/Login.tsx` around lines 28 - 40, The decodeJWT function may
call atob() on a base64url payload without proper padding; update decodeJWT to,
after replacing '-'/'_' with '+'/'/', compute padding = (4 - (base64.length %
4)) % 4 and append that many '=' characters to the base64 string before calling
atob, so the payload length is a multiple of 4 and decoding won't fail in some
browsers.

Comment on lines +3 to +10
const API_BASE_URL = "http://localhost:8080/api";

const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
"Content-Type": "application/json",
},
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Use environment variable for API base URL.

Line 3 hardcodes API_BASE_URL to localhost:8080, which will break in production and staging environments. Use an environment variable to make the URL configurable.

🔧 Proposed fix
-const API_BASE_URL = "http://localhost:8080/api";
+const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "http://localhost:8080/api";

 const apiClient = axios.create({
     baseURL: API_BASE_URL,
     headers: {
         "Content-Type": "application/json",
     },
 });

Then add to your .env files:

# .env.development
VITE_API_BASE_URL=http://localhost:8080/api

# .env.production
VITE_API_BASE_URL=https://api.yourdomain.com/api
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const API_BASE_URL = "http://localhost:8080/api";
const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
"Content-Type": "application/json",
},
});
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "http://localhost:8080/api";
const apiClient = axios.create({
baseURL: API_BASE_URL,
headers: {
"Content-Type": "application/json",
},
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/services/apiClient.ts` around lines 3 - 10, Replace the hardcoded
API_BASE_URL with a value read from the environment (VITE_API_BASE_URL) when
creating the axios instance (apiClient); use a sensible fallback (e.g.,
"http://localhost:8080/api") if the env var is missing, and keep the existing
headers and baseURL assignment in axios.create so the client behaves the same
across dev/staging/production environments. Ensure your .env files define
VITE_API_BASE_URL for each environment.

export interface VehiclePayload {
brand: string;
model: string;
imageURL?: string;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize VehiclePayload image field naming to avoid API contract mismatch.

imageURL is inconsistent with the rest of the frontend payload casing (imageUrl/logoUrl) and can cause the backend to ignore this field.

Proposed fix
 export interface VehiclePayload {
     brand: string;
     model: string;
-    imageURL?: string;
+    imageUrl?: string;
     airConditioning: boolean;
     numberOfSeats: number;
     trunkCapacity: number;
     vehicleType: string;
     companyId?: number;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
imageURL?: string;
export interface VehiclePayload {
brand: string;
model: string;
imageUrl?: string;
airConditioning: boolean;
numberOfSeats: number;
trunkCapacity: number;
vehicleType: string;
companyId?: number;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/services/company/vehicleService.ts` at line 6, The VehiclePayload
image field is named imageURL which is inconsistent with frontend casing
(imageUrl) and risks the backend ignoring it; rename the property in the
VehiclePayload type and any uses in vehicleService.ts from imageURL to imageUrl
(or map imageURL -> imageUrl when constructing the request body) so the outgoing
payload uses imageUrl consistently; update references in functions that
construct or send the payload (e.g., any create/update vehicle methods in
vehicleService) to use the new property name to preserve the API contract.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
CLAUDE.md (1)

54-54: 💤 Low value

Add language identifiers to fenced code blocks.

The three directory structure code blocks (lines 54, 70, 95) are missing language identifiers. While the content is clear, adding identifiers improves rendering and follows markdown best practices.

📝 Add language identifiers

For directory tree structures, use text or plaintext:

Line 54:

-```
+```text
 backend/src/main/java/com/angel/autonow/{domain}/

Line 70:

-```
+```text
 web/src/

Line 95:

-```
+```text
 frontend/src/

Also applies to: 70-70, 95-95

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLAUDE.md` at line 54, The three fenced code blocks showing directory trees
are missing language identifiers; update the three blocks containing
"backend/src/main/java/com/angel/autonow/{domain}/", "web/src/", and
"frontend/src/" to start with a language tag such as ```text (or ```plaintext)
so the blocks render properly and follow Markdown best practices; locate the
three fenced blocks in CLAUDE.md and prepend the language identifier to each
opening backtick fence.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@backend/src/main/resources/application.properties`:
- Line 19: The cors.allowed.origins property is hardcoded which prevents
environment-specific overrides; change it to use an environment-variable
placeholder (e.g., reference CORS_ALLOWED_ORIGINS with a sensible default equal
to the current comma-separated list) so deployments can override origins via env
vars, and ensure any startup/config code that reads cors.allowed.origins will
accept the resolved value; also update README or deploy docs to mention the
CORS_ALLOWED_ORIGINS env variable.
- Around line 15-17: The jwt.secret value is hardcoded in
application.properties—remove the literal secret and change configuration to
read from an environment variable (e.g., JWT_SECRET) so secrets aren’t
committed; update the application.properties entry for jwt.secret to reference
the env var (keeping jwt.algorithm and jwt.expiration as-is), ensure the
application fails fast or validates presence of JWT_SECRET at startup, and
rotate/regenerate the compromised secret (generate a new strong secret with
openssl rand -hex 32 and set it in the deployment environment).
- Around line 5-7: The properties file currently hardcodes DB credentials
(spring.datasource.url, spring.datasource.username, spring.datasource.password);
replace these literal values with environment-variable placeholders (e.g., use
property placeholders that reference DB_URL/DB_USER/DB_PASS) and ensure the
application reads them at runtime, then remove the hardcoded secrets from the
file; also add instructions to set those env vars (or a .env file that is added
to .gitignore) so credentials are supplied externally rather than committed.

---

Nitpick comments:
In `@CLAUDE.md`:
- Line 54: The three fenced code blocks showing directory trees are missing
language identifiers; update the three blocks containing
"backend/src/main/java/com/angel/autonow/{domain}/", "web/src/", and
"frontend/src/" to start with a language tag such as ```text (or ```plaintext)
so the blocks render properly and follow Markdown best practices; locate the
three fenced blocks in CLAUDE.md and prepend the language identifier to each
opening backtick fence.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 124d5f7e-0a89-445f-9379-8cd396a40729

📥 Commits

Reviewing files that changed from the base of the PR and between 4f2301f and 51bb972.

📒 Files selected for processing (3)
  • CLAUDE.md
  • backend/src/main/resources/application-dev.properties
  • backend/src/main/resources/application.properties
💤 Files with no reviewable changes (1)
  • backend/src/main/resources/application-dev.properties

Comment on lines +5 to +7
spring.datasource.url=jdbc:postgresql://localhost:5432/autoNow
spring.datasource.username=postgres
spring.datasource.password=12345
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Never hardcode database credentials in version control.

Hardcoding the database URL, username, and password (especially the trivial password 12345) exposes sensitive credentials in version control. If this repository is public or becomes compromised, the database is directly accessible.

🔒 Restore environment variable placeholders
-spring.datasource.url=jdbc:postgresql://localhost:5432/autoNow
-spring.datasource.username=postgres
-spring.datasource.password=12345
+spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5432/autoNow}
+spring.datasource.username=${DB_USERNAME:postgres}
+spring.datasource.password=${DB_PASSWORD}

Then set these values via environment variables or a .env file (add .env to .gitignore).

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
spring.datasource.url=jdbc:postgresql://localhost:5432/autoNow
spring.datasource.username=postgres
spring.datasource.password=12345
spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5432/autoNow}
spring.datasource.username=${DB_USERNAME:postgres}
spring.datasource.password=${DB_PASSWORD}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/resources/application.properties` around lines 5 - 7, The
properties file currently hardcodes DB credentials (spring.datasource.url,
spring.datasource.username, spring.datasource.password); replace these literal
values with environment-variable placeholders (e.g., use property placeholders
that reference DB_URL/DB_USER/DB_PASS) and ensure the application reads them at
runtime, then remove the hardcoded secrets from the file; also add instructions
to set those env vars (or a .env file that is added to .gitignore) so
credentials are supplied externally rather than committed.

Comment on lines +15 to +17
jwt.secret=8f92c3b2a9e44c8e9d6f1c4e7b2a91c8a3f5d6e8c9b1a2e4f7d8c9a1b2c3
jwt.algorithm=HS256
jwt.expiration=3600000
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Never hardcode JWT secrets in version control.

The JWT secret is used to sign all authentication tokens. Hardcoding it in version control means:

  • Any attacker with repository access can forge tokens and impersonate users
  • The secret cannot be rotated without code changes
  • Even if removed later, it remains in Git history
🔒 Restore environment variable placeholders
-jwt.secret=8f92c3b2a9e44c8e9d6f1c4e7b2a91c8a3f5d6e8c9b1a2e4f7d8c9a1b2c3
-jwt.algorithm=HS256
-jwt.expiration=3600000
+jwt.secret=${JWT_SECRET}
+jwt.algorithm=${JWT_ALGORITHM:HS256}
+jwt.expiration=${JWT_EXPIRATION:3600000}

Set JWT_SECRET to a strong random value via environment variables. Generate a new secret (this one is now compromised):

openssl rand -hex 32
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jwt.secret=8f92c3b2a9e44c8e9d6f1c4e7b2a91c8a3f5d6e8c9b1a2e4f7d8c9a1b2c3
jwt.algorithm=HS256
jwt.expiration=3600000
jwt.secret=${JWT_SECRET}
jwt.algorithm=${JWT_ALGORITHM:HS256}
jwt.expiration=${JWT_EXPIRATION:3600000}
🧰 Tools
🪛 Betterleaks (1.2.0)

[high] 15-15: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/resources/application.properties` around lines 15 - 17, The
jwt.secret value is hardcoded in application.properties—remove the literal
secret and change configuration to read from an environment variable (e.g.,
JWT_SECRET) so secrets aren’t committed; update the application.properties entry
for jwt.secret to reference the env var (keeping jwt.algorithm and
jwt.expiration as-is), ensure the application fails fast or validates presence
of JWT_SECRET at startup, and rotate/regenerate the compromised secret (generate
a new strong secret with openssl rand -hex 32 and set it in the deployment
environment).

server.port=8080

cors.allowed.origins=${CORS_ALLOWED_ORIGINS}
cors.allowed.origins=http://localhost:8080,http://localhost:8081,http://10.0.2.2:8080,http://10.0.2.2:8081
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore environment-based CORS configuration.

Hardcoding CORS allowed origins reduces deployment flexibility. Different environments (local development, staging, production) typically require different origin lists.

🔧 Restore environment variable placeholder
-cors.allowed.origins=http://localhost:8080,http://localhost:8081,http://10.0.2.2:8080,http://10.0.2.2:8081
+cors.allowed.origins=${CORS_ALLOWED_ORIGINS:http://localhost:8080,http://localhost:8081}

This allows overriding in production while keeping sensible defaults for local development.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/resources/application.properties` at line 19, The
cors.allowed.origins property is hardcoded which prevents environment-specific
overrides; change it to use an environment-variable placeholder (e.g., reference
CORS_ALLOWED_ORIGINS with a sensible default equal to the current
comma-separated list) so deployments can override origins via env vars, and
ensure any startup/config code that reads cors.allowed.origins will accept the
resolved value; also update README or deploy docs to mention the
CORS_ALLOWED_ORIGINS env variable.

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant