diff --git a/config/modules.php b/config/modules.php
index ffef4f3..b0b6e90 100644
--- a/config/modules.php
+++ b/config/modules.php
@@ -8,7 +8,6 @@ declare(strict_types=1);
*/
use App\Module\Absence\AbsenceModule;
-use App\Module\ClientPortal\ClientPortalModule;
use App\Module\Core\CoreModule;
use App\Module\Directory\DirectoryModule;
use App\Module\Integration\IntegrationModule;
@@ -26,5 +25,4 @@ return [
MailModule::class,
IntegrationModule::class,
ReportingModule::class,
- ClientPortalModule::class,
];
diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml
index 48948ad..2aeef63 100644
--- a/config/packages/doctrine.yaml
+++ b/config/packages/doctrine.yaml
@@ -26,7 +26,6 @@ doctrine:
App\Shared\Domain\Contract\TaskInterface: App\Module\ProjectManagement\Domain\Entity\Task
App\Shared\Domain\Contract\TaskTagInterface: App\Module\ProjectManagement\Domain\Entity\TaskTag
App\Shared\Domain\Contract\ClientInterface: App\Module\Directory\Domain\Entity\Client
- App\Shared\Domain\Contract\ClientTicketInterface: App\Module\ClientPortal\Domain\Entity\ClientTicket
mappings:
Core:
type: attribute
@@ -63,11 +62,6 @@ doctrine:
is_bundle: false
dir: '%kernel.project_dir%/src/Module/Integration/Domain/Entity'
prefix: 'App\Module\Integration\Domain\Entity'
- ClientPortal:
- type: attribute
- is_bundle: false
- dir: '%kernel.project_dir%/src/Module/ClientPortal/Domain/Entity'
- prefix: 'App\Module\ClientPortal\Domain\Entity'
controller_resolver:
auto_mapping: false
diff --git a/config/packages/security.yaml b/config/packages/security.yaml
index 18306fb..24cb6de 100644
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -1,6 +1,6 @@
security:
role_hierarchy:
- ROLE_ADMIN: [ROLE_USER, ROLE_CLIENT]
+ ROLE_ADMIN: [ROLE_USER]
# https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords
password_hashers:
diff --git a/config/services.yaml b/config/services.yaml
index 4e2b5af..6d11bb1 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -111,8 +111,6 @@ services:
App\Module\Directory\Domain\Repository\ClientRepositoryInterface: '@App\Module\Directory\Infrastructure\Doctrine\DoctrineClientRepository'
- App\Module\ClientPortal\Domain\Repository\ClientTicketRepositoryInterface: '@App\Module\ClientPortal\Infrastructure\Doctrine\DoctrineClientTicketRepository'
-
App\Module\Directory\Domain\Repository\ProspectRepositoryInterface: '@App\Module\Directory\Infrastructure\Doctrine\DoctrineProspectRepository'
App\Module\Mail\Domain\Repository\MailConfigurationRepositoryInterface: '@App\Module\Mail\Infrastructure\Doctrine\DoctrineMailConfigurationRepository'
diff --git a/config/sidebar.php b/config/sidebar.php
index 945b5f9..1d9ad69 100644
--- a/config/sidebar.php
+++ b/config/sidebar.php
@@ -25,7 +25,6 @@ return [
['label' => 'sidebar.general.dashboard', 'to' => '/', 'icon' => 'mdi:view-dashboard-outline'],
['label' => 'sidebar.general.myTasks', 'to' => '/my-tasks', 'icon' => 'mdi:clipboard-check-outline', 'module' => 'project-management'],
['label' => 'sidebar.general.projects', 'to' => '/projects', 'icon' => 'mdi:folder-outline', 'module' => 'project-management'],
- ['label' => 'sidebar.general.portal', 'to' => '/portal', 'icon' => 'mdi:account-box-outline', 'module' => 'client-portal'],
['label' => 'sidebar.general.timeTracking', 'to' => '/time-tracking', 'icon' => 'mdi:calendar-edit-outline', 'module' => 'time-tracking'],
// Gating module uniquement (cf. en-tête) : rendu visuel + badge gérés côté layout.
['label' => 'sidebar.general.mail', 'to' => '/mail', 'icon' => 'mdi:email-outline', 'module' => 'mail'],
@@ -37,7 +36,7 @@ return [
'roles' => ['ROLE_ADMIN'],
'items' => [
['label' => 'sidebar.admin.teamAbsences', 'to' => '/team-absences', 'icon' => 'mdi:calendar-account-outline', 'module' => 'absence'],
- ['label' => 'sidebar.admin.directory', 'to' => '/directory', 'icon' => 'mdi:contact-multiple-outline', 'module' => 'directory'],
+ ['label' => 'sidebar.admin.directory', 'to' => '/directory', 'icon' => 'mdi:card-account-details-outline', 'module' => 'directory'],
['label' => 'sidebar.admin.administration', 'to' => '/admin', 'icon' => 'mdi:cog-outline', 'permission' => 'core.users.view'],
['label' => 'sidebar.admin.reporting', 'to' => '/reporting', 'icon' => 'mdi:chart-line', 'module' => 'reporting', 'permission' => 'reporting.view'],
],
diff --git a/frontend/app/middleware/auth.global.ts b/frontend/app/middleware/auth.global.ts
index 0fec47c..4c98f1e 100644
--- a/frontend/app/middleware/auth.global.ts
+++ b/frontend/app/middleware/auth.global.ts
@@ -14,22 +14,6 @@ export default defineNuxtRouteMiddleware(async (to) => {
return navigateTo('/')
}
- // Cloisonnement portail client : un utilisateur ROLE_CLIENT "pur" (a ROLE_CLIENT
- // mais PAS ROLE_USER) n'a accès qu'aux pages /portal. Toute autre route interne
- // est redirigée vers /portal. Les ROLE_ADMIN / ROLE_USER ne sont pas concernés
- // (ils peuvent aussi visiter /portal pour prévisualiser).
- if (auth.isAuthenticated && !isLogin) {
- const roles = auth.user?.roles ?? []
- const isPureClient = roles.includes('ROLE_CLIENT') && !roles.includes('ROLE_USER')
-
- if (isPureClient) {
- const isPortalRoute = to.path === '/portal' || to.path.startsWith('/portal/')
- if (!isPortalRoute) {
- return navigateTo('/portal')
- }
- }
- }
-
const { loaded: sidebarLoaded, loadSidebar, resetSidebar } = useSidebar()
const { loaded: modulesLoaded, loadModules, resetModules } = useModules()
diff --git a/frontend/app/middleware/portal.ts b/frontend/app/middleware/portal.ts
deleted file mode 100644
index 4210bf2..0000000
--- a/frontend/app/middleware/portal.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * Named middleware for portal pages (`/portal/**`).
- * Ensures the user is authenticated. Access is open to every authenticated user
- * (ROLE_CLIENT see their portal, ROLE_ADMIN/ROLE_USER may preview it).
- */
-export default defineNuxtRouteMiddleware(() => {
- const auth = useAuthStore()
-
- if (!auth.isAuthenticated) {
- return navigateTo('/login')
- }
-})
diff --git a/frontend/components/admin/AdminClientTicketTab.vue b/frontend/components/admin/AdminClientTicketTab.vue
deleted file mode 100644
index cdb744d..0000000
--- a/frontend/components/admin/AdminClientTicketTab.vue
+++ /dev/null
@@ -1,256 +0,0 @@
-
-
-
-
{{ $t('clientTicket.adminTitle') }}
-
-
-
-
-
-
-
-
- {{ formatTicketNumber((item as ClientTicket).number) }}
-
-
-
-
-
-
-
-
-
- {{ projectName((item as ClientTicket).project) }}
-
-
- {{ submitterName((item as ClientTicket).submittedBy) }}
-
-
- {{ formatDate((item as ClientTicket).createdAt) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ formatTicketNumber(statusTicket.number) }} — {{ statusTicket.title }}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/components/notification/NotificationBell.vue b/frontend/components/notification/NotificationBell.vue
index e3e9b6d..38383e9 100644
--- a/frontend/components/notification/NotificationBell.vue
+++ b/frontend/components/notification/NotificationBell.vue
@@ -102,22 +102,11 @@ function toggleDropdown() {
}
}
-const auth = useAuthStore()
-
-const isAdmin = computed(() => (auth.user?.roles ?? []).includes('ROLE_ADMIN'))
-
function handleClick(notif: Notification) {
if (!notif.isRead) {
markAsRead(notif.id)
}
isOpen.value = false
-
- // Deep-link to the related ticket when present. The notification payload does
- // not carry the ticket's project, so we route to the relevant list view:
- // admins to the client-tickets admin tab, clients to their portal.
- if (notif.relatedTicket) {
- navigateTo(isAdmin.value ? '/admin' : '/portal')
- }
}
async function handleMarkAllRead() {
diff --git a/frontend/components/user/UserDrawer.vue b/frontend/components/user/UserDrawer.vue
index beda546..149f7e3 100644
--- a/frontend/components/user/UserDrawer.vue
+++ b/frontend/components/user/UserDrawer.vue
@@ -48,26 +48,6 @@
-
-
-
{{ $t('users.clientAccount') }}
-
-
-
-
-
-
@@ -91,8 +71,6 @@
diff --git a/frontend/modules/client-portal/components/ClientTicketFormModal.vue b/frontend/modules/client-portal/components/ClientTicketFormModal.vue
deleted file mode 100644
index 4d5d496..0000000
--- a/frontend/modules/client-portal/components/ClientTicketFormModal.vue
+++ /dev/null
@@ -1,158 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/modules/client-portal/components/ClientTicketStatusBadge.vue b/frontend/modules/client-portal/components/ClientTicketStatusBadge.vue
deleted file mode 100644
index f7d35b9..0000000
--- a/frontend/modules/client-portal/components/ClientTicketStatusBadge.vue
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
- {{ $t(`clientTicket.status.${status}`) }}
-
-
-
-
diff --git a/frontend/modules/client-portal/components/ClientTicketTypeBadge.vue b/frontend/modules/client-portal/components/ClientTicketTypeBadge.vue
deleted file mode 100644
index ed9d76c..0000000
--- a/frontend/modules/client-portal/components/ClientTicketTypeBadge.vue
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
- {{ $t(`clientTicket.type.${type}`) }}
-
-
-
-
diff --git a/frontend/modules/client-portal/nuxt.config.ts b/frontend/modules/client-portal/nuxt.config.ts
deleted file mode 100644
index 268da7f..0000000
--- a/frontend/modules/client-portal/nuxt.config.ts
+++ /dev/null
@@ -1 +0,0 @@
-export default defineNuxtConfig({})
diff --git a/frontend/modules/client-portal/pages/portal/index.vue b/frontend/modules/client-portal/pages/portal/index.vue
deleted file mode 100644
index b1d5de4..0000000
--- a/frontend/modules/client-portal/pages/portal/index.vue
+++ /dev/null
@@ -1,93 +0,0 @@
-
-
-
-
{{ $t('portal.title') }}
-
{{ $t('portal.projects') }}
-
-
-
-
-
-
-
- {{ $t('portal.noProjects') }}
-
-
-
-
-
-
- {{ project.name }}
-
-
-
-
- {{ openCount(project.id) }}
- {{ $t('portal.openTickets') }}
-
-
-
-
-
-
-
diff --git a/frontend/modules/client-portal/pages/portal/projects/[id].vue b/frontend/modules/client-portal/pages/portal/projects/[id].vue
deleted file mode 100644
index c3efba8..0000000
--- a/frontend/modules/client-portal/pages/portal/projects/[id].vue
+++ /dev/null
@@ -1,133 +0,0 @@
-
-
-
-
-
-
-
-
{{ projectName }}
-
-
-
-
-
-
-
-
-
- {{ $t('portal.noTickets') }}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/modules/client-portal/services/client-tickets.ts b/frontend/modules/client-portal/services/client-tickets.ts
deleted file mode 100644
index 2bbd652..0000000
--- a/frontend/modules/client-portal/services/client-tickets.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import type {
- ClientTicket,
- ClientTicketCreate,
- ClientTicketStatusUpdate,
-} from './dto/client-ticket'
-import type { HydraCollection } from '~/utils/api'
-import { extractHydraMembers } from '~/utils/api'
-
-export type ClientTicketFilters = {
- project?: number | string
- status?: string
- submittedBy?: number | string
-}
-
-export function useClientTicketService() {
- const api = useApi()
-
- async function getAll(params?: ClientTicketFilters): Promise
{
- const query: Record = {}
- if (params?.project !== undefined && params.project !== '') {
- query.project = typeof params.project === 'number'
- ? `/api/projects/${params.project}`
- : params.project
- }
- if (params?.status) {
- query.status = params.status
- }
- if (params?.submittedBy !== undefined && params.submittedBy !== '') {
- query.submittedBy = typeof params.submittedBy === 'number'
- ? `/api/users/${params.submittedBy}`
- : params.submittedBy
- }
- const data = await api.get>('/client_tickets', query)
- return extractHydraMembers(data)
- }
-
- async function getById(id: number): Promise {
- return api.get(`/client_tickets/${id}`)
- }
-
- async function create(payload: ClientTicketCreate): Promise {
- return api.post('/client_tickets', payload as Record, {
- toastSuccessKey: 'clientTicket.created',
- })
- }
-
- async function updateStatus(id: number, payload: ClientTicketStatusUpdate): Promise {
- return api.patch(`/client_tickets/${id}`, payload as Record, {
- toastSuccessKey: 'clientTicket.statusChanged',
- })
- }
-
- async function remove(id: number): Promise {
- await api.delete(`/client_tickets/${id}`, {}, {
- toastSuccessKey: 'clientTicket.deleted',
- })
- }
-
- return { getAll, getById, create, updateStatus, remove }
-}
diff --git a/frontend/modules/client-portal/services/dto/client-ticket.ts b/frontend/modules/client-portal/services/dto/client-ticket.ts
deleted file mode 100644
index 25f90e0..0000000
--- a/frontend/modules/client-portal/services/dto/client-ticket.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import type { TaskDocument } from '~/modules/project-management/services/dto/task-document'
-
-export type ClientTicketType = 'bug' | 'improvement' | 'other'
-export type ClientTicketStatus = 'new' | 'in_progress' | 'done' | 'rejected'
-
-export type ClientTicket = {
- '@id'?: string
- id: number
- number: number
- type: ClientTicketType
- title: string
- description: string
- url: string | null
- status: ClientTicketStatus
- statusComment: string | null
- project: string // IRI
- submittedBy: string | null // IRI, nullable (ON DELETE SET NULL)
- createdAt: string
- updatedAt: string
- documents?: TaskDocument[]
-}
-
-export type ClientTicketCreate = {
- type: ClientTicketType
- title: string
- description: string
- url?: string | null
- project: string // IRI
-}
-
-export type ClientTicketStatusUpdate = {
- status: ClientTicketStatus
- statusComment?: string | null
-}
diff --git a/frontend/modules/client-portal/utils/ticket.ts b/frontend/modules/client-portal/utils/ticket.ts
deleted file mode 100644
index 04bc09c..0000000
--- a/frontend/modules/client-portal/utils/ticket.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Format a client-ticket number for display, e.g. `CT-001`.
- */
-export function formatTicketNumber(value: number): string {
- return `CT-${String(value).padStart(3, '0')}`
-}
-
-/**
- * Extract the numeric id from an API Platform IRI (e.g. `/api/projects/5` → 5).
- * Returns null when the IRI cannot be parsed.
- */
-export function iriToId(iri: string | null | undefined): number | null {
- if (!iri) {
- return null
- }
- const match = iri.match(/(\d+)$/)
- return match ? Number(match[1]) : null
-}
diff --git a/frontend/modules/project-management/components/TaskCard.vue b/frontend/modules/project-management/components/TaskCard.vue
index 4c8a970..777087c 100644
--- a/frontend/modules/project-management/components/TaskCard.vue
+++ b/frontend/modules/project-management/components/TaskCard.vue
@@ -20,12 +20,6 @@
name="mdi:flag-variant"
class="h-3.5 w-3.5 text-red-600"
/>
-
{{ task.title }}
@@ -109,7 +103,6 @@