Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ Vue 3 + Vuetify 4 stack from Devkit. Standalone frontend or fullstack with Node/
- E2E only for critical product flows (auth, org onboarding, invite/join); requires Node + Vue + MongoDB running
- Docker (mongo + node-api): `docker compose -f docker-compose.test.yml up -d`

## Downstream config patterns

- **Config layering**: Module configs (`*.development.config.js`) load first, then global overrides (`{env}.config.js`). Override in global config, not module configs, to avoid stack merge conflicts.
- **Post-login redirect**: Set `sign.route` in global config override. Used by signin, signup, and org flows. Default: `/tasks`.

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

Use standard “sign-in/sign-up” spelling in docs text.

Line 49 uses “signin/signup”, which is flagged by static analysis and reads less clearly in prose.

📝 Suggested wording tweak
-- **Post-login redirect**: Set `sign.route` in global config override. Used by signin, signup, and org flows. Default: `/tasks`.
+- **Post-login redirect**: Set `sign.route` in global config override. Used by sign-in, sign-up, and org flows. Default: `/tasks`.
📝 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
- **Post-login redirect**: Set `sign.route` in global config override. Used by signin, signup, and org flows. Default: `/tasks`.
- **Post-login redirect**: Set `sign.route` in global config override. Used by sign-in, sign-up, and org flows. Default: `/tasks`.
🧰 Tools
🪛 LanguageTool

[grammar] ~49-~49: Ensure spelling is correct
Context: ...utein global config override. Used by signin, signup, and org flows. Default:/task...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CLAUDE.md` at line 49, Update the documentation line that currently reads
"Used by signin, signup, and org flows" to use the standard spelling
"sign-in/sign-up" (e.g., "Used by sign-in, sign-up, and org flows") while
keeping the rest of the sentence and the referenced symbol `sign.route` and
global config override intact.

- **Custom home page**: Replace `home.router.js` with a project-specific router that maps `/` to a custom view. Set `display: false` in route meta to hide from sidenav.

## Guardrails

- Never commit secrets (`.env*`, keys, tokens)
Expand Down
27 changes: 14 additions & 13 deletions src/modules/auth/tests/auth.store.unit.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, it, expect, beforeEach, vi } from 'vitest';
import { setActivePinia, createPinia } from 'pinia';
import { useAuthStore, deduceNamesFromEmail } from '../stores/auth.store';
import axios from '../../../lib/services/axios';
import config from '../../../lib/services/config';

Comment on lines 3 to 6

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

Importing ../../../lib/services/config here makes this unit test depend on the generated src/config/index.js (loaded by src/lib/services/config.js). In this repo, src/config/index.js is created by npm run generateConfig and isn’t present by default, and other unit tests avoid that by vi.mock('../../../lib/services/config', ...). To keep vitest run self-contained, mock lib/services/config in this file (and optionally set a non-devkit cookie.prefix in the mock to ensure the keys aren’t accidentally hardcoded again), or update the test runner to generate config before executing unit tests.

Copilot uses AI. Check for mistakes.
// Mock axios
vi.mock('../../../lib/services/axios', () => ({
Expand Down Expand Up @@ -51,7 +52,7 @@ describe('Auth Store', () => {

it('should initialize from localStorage', () => {
const expireTime = Date.now() + 3600000;
localStorage.setItem('devkitCookieExpire', expireTime.toString());
localStorage.setItem(`${config.cookie.prefix}CookieExpire`, expireTime.toString());

const authStore = useAuthStore();
authStore.initFromStorage();
Expand All @@ -65,18 +66,18 @@ describe('Auth Store', () => {
authStore.auth = true;
authStore.cookieExpire = Date.now() + 1000;
authStore.user = { id: '123', email: 'test@example.com' };
localStorage.setItem('devkitUserRoles', 'user,admin');
localStorage.setItem('devkitCookieExpire', '12345');
localStorage.setItem('devkitLastLoginAt', '2026-01-01T00:00:00Z');
localStorage.setItem(`${config.cookie.prefix}UserRoles`, 'user,admin');
localStorage.setItem(`${config.cookie.prefix}CookieExpire`, '12345');
localStorage.setItem(`${config.cookie.prefix}LastLoginAt`, '2026-01-01T00:00:00Z');

await authStore.signout();

expect(authStore.auth).toBe(false);
expect(authStore.cookieExpire).toBe(0);
expect(authStore.user).toBe(null);
expect(localStorage.getItem('devkitUserRoles')).toBe(null);
expect(localStorage.getItem('devkitCookieExpire')).toBe(null);
expect(localStorage.getItem('devkitLastLoginAt')).toBe(null);
expect(localStorage.getItem(`${config.cookie.prefix}UserRoles`)).toBe(null);
expect(localStorage.getItem(`${config.cookie.prefix}CookieExpire`)).toBe(null);
expect(localStorage.getItem(`${config.cookie.prefix}LastLoginAt`)).toBe(null);
});

it('should have mail state initialized', () => {
Expand All @@ -100,7 +101,7 @@ describe('Auth Store', () => {
expect(authStore.auth).toBe(true);
expect(authStore.user).toEqual(mockResponse.data.user);
expect(authStore.cookieExpire).toBe(mockResponse.data.tokenExpiresIn);
expect(localStorage.getItem('devkitUserRoles')).toBe('user');
expect(localStorage.getItem(`${config.cookie.prefix}UserRoles`)).toBe('user');
});

it('should clear lockout on successful signin', async () => {
Expand Down Expand Up @@ -132,7 +133,7 @@ describe('Auth Store', () => {
axios.post.mockResolvedValueOnce(mockResponse);
await authStore.signin({ email: 'test@test.com', password: 'password' });

expect(localStorage.getItem('devkitLastLoginAt')).toBe(lastLogin);
expect(localStorage.getItem(`${config.cookie.prefix}LastLoginAt`)).toBe(lastLogin);
});

it('should handle 423 lockout response', async () => {
Expand Down Expand Up @@ -203,7 +204,7 @@ describe('Auth Store', () => {
expect(authStore.auth).toBe(true);
expect(authStore.user).toEqual(mockResponse.data.user);
expect(authStore.cookieExpire).toBe(mockResponse.data.tokenExpiresIn);
expect(localStorage.getItem('devkitUserRoles')).toBe('user');
expect(localStorage.getItem(`${config.cookie.prefix}UserRoles`)).toBe('user');
});

it('should handle signup error', async () => {
Expand Down Expand Up @@ -233,7 +234,7 @@ describe('Auth Store', () => {
expect(authStore.auth).toBe(true);
expect(authStore.user).toEqual(mockResponse.data.user);
expect(authStore.cookieExpire).toBe(mockResponse.data.tokenExpiresIn);
expect(localStorage.getItem('devkitUserRoles')).toBe('user,admin');
expect(localStorage.getItem(`${config.cookie.prefix}UserRoles`)).toBe('user,admin');
});

it('should store lastLoginAt on token refresh', async () => {
Expand All @@ -249,7 +250,7 @@ describe('Auth Store', () => {
axios.get.mockResolvedValueOnce(mockResponse);
await authStore.token();

expect(localStorage.getItem('devkitLastLoginAt')).toBe(lastLogin);
expect(localStorage.getItem(`${config.cookie.prefix}LastLoginAt`)).toBe(lastLogin);
});

it('should handle token refresh error', async () => {
Expand Down Expand Up @@ -307,7 +308,7 @@ describe('Auth Store', () => {
expect(authStore.auth).toBe(true);
expect(authStore.user).toEqual(mockResponse.data.user);
expect(authStore.cookieExpire).toBe(mockResponse.data.tokenExpiresIn);
expect(localStorage.getItem('devkitUserRoles')).toBe('user');
expect(localStorage.getItem(`${config.cookie.prefix}UserRoles`)).toBe('user');
});

it('should handle reset password error', async () => {
Expand Down
Loading