Skip to content

Feature: Authentication model for web and tauri simulator#657

Merged
tachyons merged 18 commits intoCircuitVerse:mainfrom
ThatDeparted2061:auth
Jan 6, 2026
Merged

Feature: Authentication model for web and tauri simulator#657
tachyons merged 18 commits intoCircuitVerse:mainfrom
ThatDeparted2061:auth

Conversation

@ThatDeparted2061
Copy link
Member

@ThatDeparted2061 ThatDeparted2061 commented Sep 15, 2025

Implemented the Authentication model for the Desktop and the Vue simulator

Fixes #557
Fixes #569

Describe the changes you have made in this PR -

Screenshot from 2025-06-14 17-49-26
Screenshot from 2025-06-14 17-50-01

Video of the working Authentication model

Authentication-2.mp4

Summary by CodeRabbit

  • New Features

    • In-app authentication modal (Sign In/Register) with validation, token-based sign-in, sign-out flow, notifications badge, locale selector, and global snackbars.
  • Style

    • New dark-themed user menu styling with improved readability and visual polish.
  • Chores

    • Added icon and HTTP client dependencies, enabled HTTP plugin and permissions for authentication endpoints, and updated TypeScript types and config schema reference.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 15, 2025

Walkthrough

Adds Tauri HTTP plugin and capabilities, updates NPM and Rust manifests, initializes the plugin in the Tauri builder, and adds HTTP allow rules for two auth endpoints. Reworks the UserMenu across root, v0, and v1 variants into a right-side drawer with an in-app auth modal, snackbar feedback, and dark SCSS styles. Extends auth stores with setToken and signOut and adds TypeScript global types.

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing authentication functionality for both web and Tauri simulator platforms.
Linked Issues check ✅ Passed All primary objectives from linked issues are met: authentication UI implemented [#557], API handling for login/signup added [#557], auth store improved [#557], and authentication model drafted [#569].
Out of Scope Changes check ✅ Passed All changes are within scope: adding HTTP capabilities, implementing authentication flows, updating auth store, and styling the user menu align with the stated objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@netlify
Copy link

netlify bot commented Sep 15, 2025

Deploy Preview for circuitverse ready!

Name Link
🔨 Latest commit 70071dd
🔍 Latest deploy log https://app.netlify.com/projects/circuitverse/deploys/695d4b1d127af600084084ba
😎 Deploy Preview https://deploy-preview-657--circuitverse.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 43 (🔴 down 1 from production)
Accessibility: 73 (no change from production)
Best Practices: 92 (no change from production)
SEO: 82 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor

@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: 14

🧹 Nitpick comments (24)
tsconfig.json (1)

24-26: Confirm declaration maps and new global typings are intended

declarationMap: true ships source paths; fine for dev, avoid in production if you don’t publish d.ts. @tauri-apps/api/tauri in types is correct for Tauri globals.

If not needed, disable maps:

-        "declarationMap": true,
+        "declarationMap": false,
v0/src/components/Navbar/User/User.scss (1)

1-54: Reduce selector leakage and reliance on !important

Scope the free‑floating selectors under .userMenu and prefer theme variables over blanket !important to avoid surprising overrides and improve a11y/theming.

Apply minimal scoping:

-.avatar-menu {
+.userMenu .avatar-menu {
   background: transparent !important;
 }
 
-.avatar-btn {
+.userMenu .avatar-btn {
   text-transform: none;
   letter-spacing: normal;
 }
 
-.list-item-avatar .v-list-item-title {
+.userMenu .list-item-avatar .v-list-item-title {
   font-weight: 500;
   font-size: 1.1rem;
   color: white !important;
 }

Consider replacing hardcoded white with Vuetify tokens (e.g., color: rgb(var(--v-theme-on-surface));) in a follow‑up.

src-tauri/Cargo.toml (1)

25-25: Gate HTTP plugin and pin tauri-plugin-http

-tauri-plugin-http = "2"
+tauri-plugin-http = "2.5.2"
v1/src/store/authStore.ts (1)

89-90: Fix TODO wording.

Minor spelling/clarity.

-//  TODO: extract store verify and check better ways to impliment
+// TODO: extract store verification and explore better implementation approaches
src/components/Navbar/User/User.scss (1)

1-54: Scope and de-duplicate styles; reduce reliance on !important.

These overrides are duplicated in v1/.../User.scss and heavily use !important, which risks unintended bleed. Prefer a shared SCSS (imported in both variants) and scope under a component root class to drop most !importants.

v1/src/components/Navbar/User/User.scss (1)

1-54: Same SCSS duplicated under src/... and v1/.... Consolidate.

Keep a single User.scss and import it from both locations to avoid drift.

src/store/authStore.ts (1)

89-90: Fix TODO spelling/wording (same as v1).

-//  TODO: extract store verify and check better ways to impliment
+// TODO: extract store verification and explore better implementation approaches
src/components/Navbar/User/UserMenu.vue (3)

268-273: Standardize snackbar colors.

Mixing hex and semantic colors yields inconsistent theming. Default to a semantic color.

 const snackbar = ref({
   visible: false,
   message: '',
-  color: '#43b984'
+  color: 'success'
 })

316-323: Defensive check for server response shape before using data.token.

Prevents silent failures when the API returns a different payload.

-    const data = await response.json()
-    authStore.setToken(data.token)
+    const data = await response.json()
+    if (!data || !data.token) {
+      showSnackbar('Malformed server response', 'error')
+      return
+    }
+    authStore.setToken(data.token)

302-309: Consider using Tauri HTTP plugin in desktop to bypass CORS and honor capabilities.

In Tauri, prefer @tauri-apps/plugin-http for the auth calls; fall back to window.fetch on web.

// example (outside of diff scope)
// import { fetch as tFetch } from '@tauri-apps/plugin-http'
const doFetch = (window as any).__TAURI__ ? (window as any).__TAURI_HTTP_FETCH__ ?? fetch : fetch
// then: const response = await doFetch(url, { method: 'POST', headers: {...}, body: ... })
v1/src/components/Navbar/User/UserMenu.vue (8)

316-323: Validate token presence before storing.

Avoid setting an undefined token; surface a clear error.

-    const data = await response.json()
-    authStore.setToken(data.token)
+    const data = await response.json()
+    if (!data?.token) {
+      throw new Error('No token received from server')
+    }
+    authStore.setToken(data.token)

26-33: Prevent broken avatar when using a 'default' sentinel.

Guard prepend-avatar to avoid passing a non-URL string.

-          :prepend-avatar="authStore.getUserAvatar"
+          :prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
           :prepend-icon="
             authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
           "

231-236: Fix snackbar close button icon and drop unused import.

Use a standard icon name; avoid mixing @mdi/js path usage with Vuetify defaults.

-import { mdiClose } from '@mdi/js'
 import './User.scss'
-        <v-btn
-          variant="text"
-          @click="snackbar.visible = false"
-          :icon="mdiClose"
-          color="white"
-        ></v-btn>
+        <v-btn variant="text" @click="snackbar.visible = false" color="white">
+          <v-icon>mdi-close</v-icon>
+        </v-btn>

Also applies to: 247-249


258-266: Type the VForm ref for TS safety.

Prevents “any” leakage on validate().

-import { ref } from 'vue'
+import { ref } from 'vue'
+import type { VForm } from 'vuetify/components'
-const authForm = ref()
+const authForm = ref<VForm | null>(null)

Also applies to: 242-246


164-173: Add autocomplete attributes for better UX/security.

Improve autofill and password manager behavior.

-            <v-text-field 
+            <v-text-field 
               v-if="!isLoginMode" 
               v-model="name" 
               label="Name" 
               type="text"
               :rules="[requiredRule]"
               variant="outlined"
               class="mb-0"
               bg-color="#f0eee6"
+              autocomplete="name"
             ></v-text-field>
-            <v-text-field
+            <v-text-field
               v-model="email"
               label="Email"
               type="email"
               :rules="[requiredRule, emailRule]"
               variant="outlined"
               class="mb-0"
               bg-color="#f0eee6"
+              autocomplete="email"
             ></v-text-field>
-            <v-text-field
+            <v-text-field
               v-model="password"
               label="Password"
               type="password"
               :rules="[requiredRule, passwordRule]"
               variant="outlined"
               class="mb-0"
               bg-color="#f0eee6"
+              :autocomplete="isLoginMode ? 'current-password' : 'new-password'"
             ></v-text-field>

Also applies to: 174-183, 184-193


370-373: Close the drawer on logout.

Minor UX polish.

 function signout() {
   authStore.signOut()
   showSnackbar('You have been logged out', 'info')
+  drawer.value = false
 }

358-368: Prefer router navigation over full page reloads.

Use useRouter().push for SPA behavior.

-import { ref } from 'vue'
+import { ref } from 'vue'
+import { useRouter } from 'vue-router'
...
-function dashboard() {
-  window.location.href = `/users/${authStore.getUserId}`
-}
+const router = useRouter()
+function dashboard() {
+  router.push(`/users/${authStore.getUserId}`)
+}
...
-  window.location.href = `/users/${authStore.getUserId}/groups`
+  router.push(`/users/${authStore.getUserId}/groups`)
...
-  window.location.href = `/users/${authStore.getUserId}/notifications`
+  router.push(`/users/${authStore.getUserId}/notifications`)

2-205: Externalize UI strings to i18n ($t)
Replace all hard-coded labels in v1/src/components/Navbar/User/UserMenu.vue (lines 2–205; also 221–236, 248–356) with $t keys to enable localization. Generate a keys map + migration diff?

v0/src/components/Navbar/User/UserMenu.vue (6)

24-34: Prevent broken avatar when using a 'default' sentinel.

-        <v-list-item
+        <v-list-item
           class="list-item-avatar"
-          :prepend-avatar="authStore.getUserAvatar"
+          :prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
           :prepend-icon="
             authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
           "
           :title="authStore.getUsername"
           lines="two"
           color="white"
         ></v-list-item>

227-233: Fix snackbar close icon and remove unused mdiClose import.

-import { mdiClose } from '@mdi/js'
-import { fetch } from '@tauri-apps/plugin-http'
+import { fetch } from '@tauri-apps/plugin-http'
-        <v-btn
-          variant="text"
-          @click="snackbar.visible = false"
-          :icon="mdiClose"
-          color="white"
-        ></v-btn>
+        <v-btn variant="text" @click="snackbar.visible = false" color="white">
+          <v-icon>mdi-close</v-icon>
+        </v-btn>

Also applies to: 243-246


256-257: Type the VForm ref for TS safety.

-import { ref } from 'vue'
+import { ref } from 'vue'
+import type { VForm } from 'vuetify/components'
-const authForm = ref()
+const authForm = ref<VForm | null>(null)

Also applies to: 238-246


159-168: Add autocomplete attributes to form fields.

-            <v-text-field 
+            <v-text-field 
               v-if="!isLoginMode" 
               v-model="name" 
               label="Name" 
               type="text"
               :rules="[requiredRule]"
               variant="outlined"
               class="mb-0"
               bg-color="#f0eee6"
+              autocomplete="name"
             ></v-text-field>
-            <v-text-field
+            <v-text-field
               v-model="email"
               label="Email"
               type="email"
               :rules="[requiredRule, emailRule]"
               variant="outlined"
               class="mb-0"
               bg-color="#f0eee6"
+              autocomplete="email"
             ></v-text-field>
-            <v-text-field
+            <v-text-field
               v-model="password"
               label="Password"
               type="password"
               :rules="[requiredRule, passwordRule]"
               variant="outlined"
               class="mb-0"
               bg-color="#f0eee6"
+              :autocomplete="isLoginMode ? 'current-password' : 'new-password'"
             ></v-text-field>

Also applies to: 170-179, 180-189


380-383: Close the drawer on logout.

 function signout() {
   authStore.signOut()
   showSnackbar('You have been logged out', 'info')
+  drawer.value = false
 }

368-378: Prefer router navigation over full reloads.

-  window.location.href = `/users/${authStore.getUserId}`
+  router.push(`/users/${authStore.getUserId}`)
...
-  window.location.href = `/users/${authStore.getUserId}/groups`
+  router.push(`/users/${authStore.getUserId}/groups`)
...
-  window.location.href = `/users/${authStore.getUserId}/notifications`
+  router.push(`/users/${authStore.getUserId}/notifications`)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1ff6c5 and 1defa91.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • package.json (1 hunks)
  • src-tauri/Cargo.toml (1 hunks)
  • src-tauri/capabilities/default.json (1 hunks)
  • src-tauri/src/lib.rs (1 hunks)
  • src-tauri/tauri.conf.json (2 hunks)
  • src/components/Navbar/User/User.scss (1 hunks)
  • src/components/Navbar/User/UserMenu.vue (1 hunks)
  • src/store/authStore.ts (2 hunks)
  • tsconfig.json (1 hunks)
  • v0/src/components/Navbar/User/User.scss (1 hunks)
  • v0/src/components/Navbar/User/UserMenu.vue (1 hunks)
  • v0/src/store/authStore.ts (2 hunks)
  • v1/src/components/Navbar/User/User.scss (1 hunks)
  • v1/src/components/Navbar/User/UserMenu.vue (1 hunks)
  • v1/src/store/authStore.ts (2 hunks)
🔇 Additional comments (5)
package.json (2)

19-19: MDI JS addition looks fine

No concerns adding @mdi/js for icons.


22-22: Keep JS/Rust HTTP plugin versions in sync

package.json: @tauri-apps/plugin-http = ^2.5.2; src-tauri/Cargo.toml: tauri-plugin-http = "2" — both are major v2 and compatible. No immediate change required; pin matching minor versions only if you depend on features introduced in >=2.5.2.

src-tauri/tauri.conf.json (1)

2-2: Schema path update LGTM

Looks correct for Tauri 2 CLI schema. No action needed.

src-tauri/src/lib.rs (1)

7-7: Initialize HTTP plugin: verify capability covers only required endpoints

The init is correct. Double‑check the src-tauri/capabilities/default.json includes http:default with a tight allow‑list (login/signup) so requests are actually permitted but limited. (v2.tauri.app)

v1/src/store/authStore.ts (1)

58-65: Clear persisted auth token on sign-out; don't force locale reset.

signOut() in v1/src/store/authStore.ts currently sets locale = 'en' and does not remove any persisted auth token — if the JWT is persisted, remove it here (e.g. localStorage.removeItem('') or call the project's token-removal utility) and stop overriding locale unless you intentionally want to revert to a guest default.

Location: v1/src/store/authStore.ts — signOut().

Comment on lines +320 to +326
const data = await response.json()
console.log('Auth successful:', data)

if (!data.token) {
throw new Error('No token received from server')
}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove sensitive console logs and harden error handling.

Never log auth payloads/tokens; normalize error message extraction.

-    const data = await response.json()
-    console.log('Auth successful:', data)
+    const data = await response.json()
...
-  } catch (error) {
-    console.error('Authentication error:', error)
-    showSnackbar(`Authentication failed: ${error.message}`, 'error')
+  } catch (error: unknown) {
+    console.error('Authentication error')
+    const message = error instanceof Error ? error.message : String(error)
+    showSnackbar(`Authentication failed: ${message}`, 'error')

Also applies to: 334-335

@ThatDeparted2061
Copy link
Member Author

@aryanndwi123 @tachyons I have added the video showing the working of the auth model

this.signOut()
return
}
},
Copy link
Member

Choose a reason for hiding this comment

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

You can use jwt package to verify this

@tachyons
Copy link
Member

tachyons commented Jan 6, 2026

there are improvements we can make here, but I'm merging this for now to enable community contributions

@tachyons tachyons merged commit f071795 into CircuitVerse:main Jan 6, 2026
9 of 10 checks passed
Copy link
Contributor

@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: 13

🤖 Fix all issues with AI Agents
In @src/components/Navbar/User/UserMenu.vue:
- Around line 291-306: The API base URL is hard-coded to http://localhost:4000;
update the construction of url inside the login/signup flow (the url const that
depends on isLoginMode.value) to use a configurable environment variable (e.g.
import.meta.env.VITE_API_BASE or process.env.API_BASE) with a sensible default,
then append the path '/api/v1/auth/login' or '/api/v1/auth/signup' to that base;
ensure the fetch call that currently uses url, headers and body remains
unchanged but now targets the environment-driven base so production/HTTPS
environments are supported.
- Around line 24-33: The v-list-item is passing the literal 'default' string
into :prepend-avatar which makes Vuetify try to load it as an image; change the
binding to only provide the avatar URL when authStore.getUserAvatar !==
'default' (e.g. :prepend-avatar="authStore.getUserAvatar !== 'default' ?
authStore.getUserAvatar : undefined") and keep the prepend-icon conditional
(authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' :
undefined) so the broken image is avoided and the fallback icon is shown.
- Around line 320-321: Remove the sensitive console.log call that prints the
full auth response; do not log the result of response.json() (the data variable)
as it may contain tokens. Instead, either remove the console.log entirely or
replace it with a non-sensitive success indicator (e.g., log a static "Auth
successful" message or only safe fields such as user id/username after explicit
filtering). Update the code around the response.json() usage (the data variable
and the console.log('Auth successful:', data) line) to avoid exposing auth
payloads.
- Around line 333-335: The catch block in UserMenu.vue accesses error.message
directly even though `error` is `unknown`; update the catch to type-guard the
error before using `.message` (e.g., check `error instanceof Error` or use a
utility like `isError`) and pass a safe string to showSnackbar and
console.error; specifically modify the catch around the authentication code that
currently calls console.error('Authentication error:', error) and
showSnackbar(`Authentication failed: ${error.message}`, 'error') to log the raw
value and derive a message via the type guard (fallback to String(error) or a
default message) before calling showSnackbar.

In @v0/src/components/Navbar/User/UserMenu.vue:
- Around line 291-306: The fetch uses a hard-coded 'http://localhost:4000' which
will break production; change the login/signup URL construction in the
UserMenu.vue block that uses isLoginMode to build the request so it reads the
API base from an environment variable (e.g., import.meta.env.VITE_API_BASE_URL
or process.env.VUE_APP_API_URL) and concatenate the path '/api/v1/auth/login' or
'/api/v1/auth/signup' accordingly; ensure you handle missing trailing slash and
provide a sensible fallback or throw a clear error so both the URL variable and
the fetch using isLoginMode, body, and response remain functional in all
environments.
- Around line 320-321: Remove the sensitive console.log call that prints the
full auth response: delete or replace "console.log('Auth successful:', data)" in
the auth handler so you do not output tokens or credentials; if you need debug
info, log only non-sensitive fields from the parsed response (e.g., user id or
status) or use a secure logger that redacts tokens before logging within the
function that calls response.json().

In @v0/src/store/authStore.ts:
- Around line 70-77: The signOut method currently resets in-memory fields but
doesn't clear the persisted token; update the signOut function to also remove
the stored token by calling localStorage.removeItem('cv_token') (matching the
key used in setToken) so no stale token remains after logout. Ensure this change
is applied inside the same signOut method in authStore.ts alongside clearing
isLoggedIn, userId, username, userAvatar, locale, and isAdmin.

In @v1/src/components/Navbar/User/UserMenu.vue:
- Around line 320-321: Remove the sensitive console.log call that prints the
full auth response; locate the console.log('Auth successful:', data) after the
await response.json() and delete it or replace it with a safe log that only
outputs non-sensitive status (e.g., data.user?.id or a boolean success flag). If
you must log parts of data, explicitly redact tokens/credentials (e.g., remove
or mask data.token / data.access_token) before logging to ensure no auth tokens
are emitted to the console.
- Around line 24-33: The v-list-item currently passes authStore.getUserAvatar
directly to :prepend-avatar which causes a broken image when the value is the
literal string 'default'; change the binding so :prepend-avatar only receives a
real avatar URL (e.g., set it to undefined when authStore.getUserAvatar ===
'default') and keep the existing :prepend-icon fallback logic that checks
authStore.getUserAvatar === 'default'; update the template bindings around the
v-list-item (:prepend-avatar, :prepend-icon, authStore.getUserAvatar) to
implement this conditional so the default case uses the icon instead of
rendering a broken image.
- Around line 333-335: The catch block in UserMenu.vue accesses error.message
directly which can throw if error is not an Error; update the catch to
type-guard the caught value (e.g., use "error instanceof Error" or check typeof
error === 'object' && 'message' in error) and pass a safe string to showSnackbar
(fallback to String(error) or a generic message) and log accordingly; apply the
same pattern to all similar catch handlers that call showSnackbar with
error.message.

In @v1/src/store/authStore.ts:
- Around line 70-77: Update the signOut method in authStore.ts to also remove
the persisted auth token from localStorage: call localStorage.removeItem(...)
using the same storage key the app uses for the token (or reference the existing
TOKEN_STORAGE_KEY / get/set token utility if one exists) before resetting
isLoggedIn/userId/username/etc., so signing out clears the stored token.
🧹 Nitpick comments (2)
v0/src/store/authStore.ts (1)

33-58: JWT handling implementation looks correct.

The base64url decoding and expiration validation are properly implemented. Minor nit: Line 49 has inconsistent indentation (extra leading space before this.userId).

🔎 Fix indentation
                this.isLoggedIn = true
-               this.userId = payload.user_id ?? payload.sub ?? ''
+                this.userId = payload.user_id ?? payload.sub ?? ''
                this.username = payload.username ?? 'Guest'
v1/src/store/authStore.ts (1)

33-58: JWT handling implementation looks correct.

Same as v0 variant - base64url decoding and expiration validation are properly implemented. Same minor indentation issue on Line 49.

🔎 Fix indentation
                this.isLoggedIn = true
-               this.userId = payload.user_id ?? payload.sub ?? ''
+                this.userId = payload.user_id ?? payload.sub ?? ''
                this.username = payload.username ?? 'Guest'
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1defa91 and 70071dd.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • src/components/Navbar/User/UserMenu.vue
  • src/store/authStore.ts
  • v0/src/components/Navbar/User/UserMenu.vue
  • v0/src/store/authStore.ts
  • v1/src/components/Navbar/User/UserMenu.vue
  • v1/src/store/authStore.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/store/authStore.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-12-30T10:11:52.399Z
Learnt from: senutpal
Repo: CircuitVerse/cv-frontend-vue PR: 706
File: .github/workflows/tauri-release.yml:51-51
Timestamp: 2025-12-30T10:11:52.399Z
Learning: In cv-frontend-vue repository, the tauri-action's `projectPath` should be set to `.` (root) because the `beforeBuildCommand` needs to run from the root directory where `package.json` and `dist/` are located. The Tauri CLI automatically locates `src-tauri/tauri.conf.json` from the project root.

Applied to files:

  • src/components/Navbar/User/UserMenu.vue

Comment on lines +24 to +33
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Passing 'default' to :prepend-avatar renders a broken image.

When getUserAvatar is 'default', the prepend-avatar prop receives the literal string 'default' which Vuetify will try to load as an image URL, resulting in a broken image alongside the fallback icon.

🔎 Proposed fix
         <v-list-item
           class="list-item-avatar"
-          :prepend-avatar="authStore.getUserAvatar"
+          :prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
           :prepend-icon="
             authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
           "
📝 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
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
🤖 Prompt for AI Agents
In @src/components/Navbar/User/UserMenu.vue around lines 24 - 33, The
v-list-item is passing the literal 'default' string into :prepend-avatar which
makes Vuetify try to load it as an image; change the binding to only provide the
avatar URL when authStore.getUserAvatar !== 'default' (e.g.
:prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar
: undefined") and keep the prepend-icon conditional (authStore.getUserAvatar ===
'default' ? 'mdi-account-circle-outline' : undefined) so the broken image is
avoided and the fallback icon is shown.

Comment on lines +291 to +306
const url = isLoginMode.value
? 'http://localhost:4000/api/v1/auth/login'
: 'http://localhost:4000/api/v1/auth/signup'

const body = isLoginMode.value
? { email: email.value, password: password.value }
: { email: email.value, password: password.value, name: name.value }

const response = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Hard-coded localhost:4000 breaks production and HTTPS environments.

This will fail in production. Use an environment variable for the API base URL.

🔎 Proposed fix
-    const url = isLoginMode.value
-      ? 'http://localhost:4000/api/v1/auth/login'
-      : 'http://localhost:4000/api/v1/auth/signup'
+    const API_BASE = import.meta.env.VITE_API_BASE_URL ?? 'https://circuitverse.org'
+    const url = `${API_BASE}/api/v1/auth/${isLoginMode.value ? 'login' : 'signup'}`
📝 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 url = isLoginMode.value
? 'http://localhost:4000/api/v1/auth/login'
: 'http://localhost:4000/api/v1/auth/signup'
const body = isLoginMode.value
? { email: email.value, password: password.value }
: { email: email.value, password: password.value, name: name.value }
const response = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
})
const API_BASE = import.meta.env.VITE_API_BASE_URL ?? 'https://circuitverse.org'
const url = `${API_BASE}/api/v1/auth/${isLoginMode.value ? 'login' : 'signup'}`
const body = isLoginMode.value
? { email: email.value, password: password.value }
: { email: email.value, password: password.value, name: name.value }
const response = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
})
🤖 Prompt for AI Agents
In @src/components/Navbar/User/UserMenu.vue around lines 291 - 306, The API base
URL is hard-coded to http://localhost:4000; update the construction of url
inside the login/signup flow (the url const that depends on isLoginMode.value)
to use a configurable environment variable (e.g. import.meta.env.VITE_API_BASE
or process.env.API_BASE) with a sensible default, then append the path
'/api/v1/auth/login' or '/api/v1/auth/signup' to that base; ensure the fetch
call that currently uses url, headers and body remains unchanged but now targets
the environment-driven base so production/HTTPS environments are supported.

Comment on lines +320 to +321
const data = await response.json()
console.log('Auth successful:', data)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove sensitive console log that may expose auth tokens.

Logging the full data response object could expose tokens or other sensitive auth payload data in browser dev tools or log aggregators.

🔎 Proposed fix
     const data = await response.json()
-    console.log('Auth successful:', data)
📝 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 data = await response.json()
console.log('Auth successful:', data)
const data = await response.json()
🤖 Prompt for AI Agents
In @src/components/Navbar/User/UserMenu.vue around lines 320 - 321, Remove the
sensitive console.log call that prints the full auth response; do not log the
result of response.json() (the data variable) as it may contain tokens. Instead,
either remove the console.log entirely or replace it with a non-sensitive
success indicator (e.g., log a static "Auth successful" message or only safe
fields such as user id/username after explicit filtering). Update the code
around the response.json() usage (the data variable and the console.log('Auth
successful:', data) line) to avoid exposing auth payloads.

Comment on lines +333 to +335
} catch (error) {
console.error('Authentication error:', error)
showSnackbar(`Authentication failed: ${error.message}`, 'error')
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Type-guard the error before accessing .message.

error is of type unknown in catch blocks. Accessing .message directly will fail TypeScript strict checks.

🔎 Proposed fix
   } catch (error) {
-    console.error('Authentication error:', error)
-    showSnackbar(`Authentication failed: ${error.message}`, 'error')
+    console.error('Authentication error')
+    const message = error instanceof Error ? error.message : String(error)
+    showSnackbar(`Authentication failed: ${message}`, 'error')
   } finally {
📝 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
} catch (error) {
console.error('Authentication error:', error)
showSnackbar(`Authentication failed: ${error.message}`, 'error')
} catch (error) {
console.error('Authentication error')
const message = error instanceof Error ? error.message : String(error)
showSnackbar(`Authentication failed: ${message}`, 'error')
🤖 Prompt for AI Agents
In @src/components/Navbar/User/UserMenu.vue around lines 333 - 335, The catch
block in UserMenu.vue accesses error.message directly even though `error` is
`unknown`; update the catch to type-guard the error before using `.message`
(e.g., check `error instanceof Error` or use a utility like `isError`) and pass
a safe string to showSnackbar and console.error; specifically modify the catch
around the authentication code that currently calls
console.error('Authentication error:', error) and showSnackbar(`Authentication
failed: ${error.message}`, 'error') to log the raw value and derive a message
via the type guard (fallback to String(error) or a default message) before
calling showSnackbar.

Comment on lines +24 to +33
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Passing 'default' to :prepend-avatar renders a broken image.

Same issue as root variant.

🔎 Proposed fix
         <v-list-item
           class="list-item-avatar"
-          :prepend-avatar="authStore.getUserAvatar"
+          :prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
           :prepend-icon="
             authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
           "
📝 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
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>

Comment on lines +24 to +33
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Passing 'default' to :prepend-avatar renders a broken image.

Same issue across all UserMenu.vue variants.

🔎 Proposed fix
         <v-list-item
           class="list-item-avatar"
-          :prepend-avatar="authStore.getUserAvatar"
+          :prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
           :prepend-icon="
             authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
           "
📝 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
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
<v-list-item
class="list-item-avatar"
:prepend-avatar="authStore.getUserAvatar !== 'default' ? authStore.getUserAvatar : undefined"
:prepend-icon="
authStore.getUserAvatar === 'default' ? 'mdi-account-circle-outline' : undefined
"
:title="authStore.getUsername"
lines="two"
color="white"
></v-list-item>
🤖 Prompt for AI Agents
In @v1/src/components/Navbar/User/UserMenu.vue around lines 24 - 33, The
v-list-item currently passes authStore.getUserAvatar directly to :prepend-avatar
which causes a broken image when the value is the literal string 'default';
change the binding so :prepend-avatar only receives a real avatar URL (e.g., set
it to undefined when authStore.getUserAvatar === 'default') and keep the
existing :prepend-icon fallback logic that checks authStore.getUserAvatar ===
'default'; update the template bindings around the v-list-item (:prepend-avatar,
:prepend-icon, authStore.getUserAvatar) to implement this conditional so the
default case uses the icon instead of rendering a broken image.

Comment on lines +291 to +306
const url = isLoginMode.value
? 'http://localhost:4000/api/v1/auth/login'
: 'http://localhost:4000/api/v1/auth/signup'

const body = isLoginMode.value
? { email: email.value, password: password.value }
: { email: email.value, password: password.value, name: name.value }

const response = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(body)
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Hard-coded localhost:4000 breaks production.

Same issue across all UserMenu.vue variants - use environment variable.

Comment on lines +320 to +321
const data = await response.json()
console.log('Auth successful:', data)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove sensitive console log.

Same issue across all variants - may expose auth tokens.

🤖 Prompt for AI Agents
In @v1/src/components/Navbar/User/UserMenu.vue around lines 320 - 321, Remove
the sensitive console.log call that prints the full auth response; locate the
console.log('Auth successful:', data) after the await response.json() and delete
it or replace it with a safe log that only outputs non-sensitive status (e.g.,
data.user?.id or a boolean success flag). If you must log parts of data,
explicitly redact tokens/credentials (e.g., remove or mask data.token /
data.access_token) before logging to ensure no auth tokens are emitted to the
console.

Comment on lines +333 to +335
} catch (error) {
console.error('Authentication error:', error)
showSnackbar(`Authentication failed: ${error.message}`, 'error')
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Type-guard the error before accessing .message.

Same fix needed across all variants.

🔎 Proposed fix
   } catch (error) {
-    console.error('Authentication error:', error)
-    showSnackbar(`Authentication failed: ${error.message}`, 'error')
+    console.error('Authentication error')
+    const message = error instanceof Error ? error.message : String(error)
+    showSnackbar(`Authentication failed: ${message}`, 'error')
   } finally {
🤖 Prompt for AI Agents
In @v1/src/components/Navbar/User/UserMenu.vue around lines 333 - 335, The catch
block in UserMenu.vue accesses error.message directly which can throw if error
is not an Error; update the catch to type-guard the caught value (e.g., use
"error instanceof Error" or check typeof error === 'object' && 'message' in
error) and pass a safe string to showSnackbar (fallback to String(error) or a
generic message) and log accordingly; apply the same pattern to all similar
catch handlers that call showSnackbar with error.message.

Comment on lines +70 to +77
signOut(): void {
this.isLoggedIn = false
this.userId = ''
this.username = 'Guest'
this.userAvatar = 'default'
this.locale = 'en'
this.isAdmin = false
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

signOut should clear persisted token from localStorage.

Same issue as v0 variant - persisted token not cleared on sign-out.

🔎 Proposed fix
         signOut(): void {
             this.isLoggedIn = false
             this.userId = ''
             this.username = 'Guest'
             this.userAvatar = 'default'
             this.locale = 'en'
             this.isAdmin = false
+            try { if (typeof localStorage !== 'undefined') localStorage.removeItem('cv_token') } catch {}
         },
📝 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
signOut(): void {
this.isLoggedIn = false
this.userId = ''
this.username = 'Guest'
this.userAvatar = 'default'
this.locale = 'en'
this.isAdmin = false
},
signOut(): void {
this.isLoggedIn = false
this.userId = ''
this.username = 'Guest'
this.userAvatar = 'default'
this.locale = 'en'
this.isAdmin = false
try { if (typeof localStorage !== 'undefined') localStorage.removeItem('cv_token') } catch {}
},
🤖 Prompt for AI Agents
In @v1/src/store/authStore.ts around lines 70 - 77, Update the signOut method in
authStore.ts to also remove the persisted auth token from localStorage: call
localStorage.removeItem(...) using the same storage key the app uses for the
token (or reference the existing TOKEN_STORAGE_KEY / get/set token utility if
one exists) before resetting isLoggedIn/userId/username/etc., so signing out
clears the stored token.

@ThatDeparted2061
Copy link
Member Author

Yeah sure we ll do that. We also need to add authentication through google etc too. I ll raise an issue for the same

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.

Draft the User Authentication Model Feature : Authentication for simulator - Web and Tauri

2 participants