Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
release:
uses: saucebase-dev/saucebase/.github/workflows/semantic-release.yml@main
with:
version_file: 'module.json'
version_file: 'composer.json'
version_file_path: '.version'
prerelease: false
secrets:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ jobs:
test:
uses: saucebase-dev/saucebase/.github/workflows/test-module.yml@main
with:
module: Auth
module: auth
frameworks: '["vue","react"]'
10 changes: 9 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ Authentication, registration, magic link (passwordless), password reset, email v
| Layout | `AuthCardLayout` — card with logo, status alerts, page transitions |
| Component | `SocialiteProviders` — Google/GitHub buttons with divider |

## Frontend

Follows the dual-framework pattern (see root `CLAUDE.md` → Architecture > Frontend).

- Both `resources/js/vue/` and `resources/js/react/` exist and must stay in sync
- `resources/js/app.ts` is a generated re-export — do not edit it directly
- `registerIcon()`, `registerAction()`, `registerGlobalComponent()` calls in `setup()` must be mirrored in both framework implementations

## Routes

**Guest routes** (`/auth/*`): login (GET/POST), register (GET/POST), forgot-password (GET/POST), reset-password/{token} (GET, signed), reset-password (POST, throttle:6,1), magic-link (GET/POST, throttle:5,1)
Expand Down Expand Up @@ -74,7 +82,7 @@ Redirect URIs default to `/auth/socialite/{provider}/callback`. Providers config

```bash
php artisan test --testsuite=Modules --filter='^Modules\\Auth\\Tests' # PHPUnit
npx playwright test --project="@Auth*" # E2E
npx playwright test --project="@auth*" # E2E
```

**E2E coverage**: login (basic, errors, security/rate-limiting, social, logout), register (basic, errors), forgot-password (basic, errors), verify-email. Page objects in `tests/e2e/pages/`, fixtures in `tests/e2e/fixtures/users.ts`.
Expand Down
10 changes: 8 additions & 2 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,17 @@ tasks:

test:e2e:
desc: Run E2E tests for Auth module
cmd: npx playwright test --project="@Auth*" {{.CLI_ARGS}}
cmd: npx playwright test --project="@auth*" {{.CLI_ARGS}}
interactive: true

# ── Database ──────────────────────────────────────────────────

db:seed:
desc: Seed the Auth module database
cmd: php artisan modules:seed --module=auth

# ── Code Generation ────────────────────────────────────────────

types:generate:
desc: Generate TypeScript types from PHP DTOs and enums
cmd: php artisan module:generate-types Auth
cmd: php artisan module:generate-types auth
17 changes: 0 additions & 17 deletions app/Providers/RouteServiceProvider.php

This file was deleted.

13 changes: 9 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
{
"name": "saucebase/auth",
"description": "",
"description": "Authentication module for Saucebase",
"type": "saucebase-module",
"license": "proprietary",
"version": "1.8.1",
"authors": [
{
"name": "Saucebase",
Expand All @@ -10,13 +12,15 @@
],
"extra": {
"laravel": {
"providers": [],
"providers": [
"Modules\\Auth\\Providers\\AuthServiceProvider"
],
"aliases": {}
}
},
"autoload": {
"psr-4": {
"Modules\\Auth\\": "app/",
"Modules\\Auth\\": "src/",
"Modules\\Auth\\Database\\Factories\\": "database/factories/",
"Modules\\Auth\\Database\\Seeders\\": "database/seeders/"
}
Expand All @@ -29,5 +33,6 @@
"require": {
"laravel/socialite": "^5.21",
"stechstudio/filament-impersonate": "^5.1"
}
},
"minimum-stability": "stable"
}
18 changes: 18 additions & 0 deletions database/seeders/DatabaseSeeder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Modules\Auth\Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
public function run(): void
{
if (! app()->environment(['local', 'testing'])) {
return;
}

$this->call(AuthDatabaseSeeder::class);
}
Comment thread
roble marked this conversation as resolved.
}
}
15 changes: 0 additions & 15 deletions module.json

This file was deleted.

56 changes: 1 addition & 55 deletions resources/js/app.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1 @@
import { useDialog } from '@/composables/useDialog';
import { registerGlobalComponent } from '@/lib/globalComponents';
import { registerAction, registerIcon } from '@/lib/navigation';
import { router } from '@inertiajs/vue3';
import { trans } from 'laravel-vue-i18n';
import { LogOut } from 'lucide-vue-next';
import IconLogOut from '~icons/lucide/log-out';
import ImpersonationAlert from './components/ImpersonationAlert.vue';

import '../css/style.css';

/**
* Auth module setup
* Called during app initialization before mounting
*/
export function setup() {
registerIcon('logout', IconLogOut);
registerAuthActions();
registerGlobalComponent('top', ImpersonationAlert);
}

/**
* Register auth-related navigation actions
*/
function registerAuthActions() {
// Logout action
registerAction('logout', async (event: MouseEvent) => {
event.preventDefault();

const { confirm } = useDialog();
if (
await confirm({
title: trans('Log out'),
description: trans(
'Are you sure you want to log out? You will need to sign in again.',
),
confirmLabel: trans('Log out'),
cancelLabel: trans('Cancel'),
variant: 'destructive',
icon: LogOut,
align: 'left',
})
) {
router.post(route('logout'));
}
});
}

/**
* Auth module after mount logic
* Called after the app has been mounted
*/
export function afterMount() {
console.debug('Auth module after mount logic executed');
}
export * from './vue/app';
39 changes: 39 additions & 0 deletions resources/js/react/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { confirm } from '@/hooks/useDialog';
import { registerGlobalComponent } from '@/lib/globalComponents';
import { registerAction, registerIcon } from '@/lib/navigation';
import { router } from '@inertiajs/react';
import '@modules/auth/resources/css/style.css';
import { LogOut } from 'lucide-react';
import IconLogOut from '~icons/lucide/log-out';
import ImpersonationAlert from './components/ImpersonationAlert';

export function setup() {
registerIcon('logout', IconLogOut);
registerAuthActions();
registerGlobalComponent('top', ImpersonationAlert);
}

function registerAuthActions() {
registerAction('logout', async (event: MouseEvent) => {
event.preventDefault();

const confirmed = await confirm({
title: 'Log out',
description:
'Are you sure you want to log out? You will need to sign in again.',
confirmLabel: 'Log out',
cancelLabel: 'Cancel',
variant: 'destructive',
icon: LogOut,
align: 'left',
});

if (confirmed) {
router.post(route('logout'));
}
});
}

export function afterMount() {
console.debug('Auth module after mount logic executed');
}
Loading
Loading