diff --git a/apps/web/src/routes/app/+layout.server.ts b/apps/web/src/routes/app/+layout.server.ts
new file mode 100644
index 0000000..7164642
--- /dev/null
+++ b/apps/web/src/routes/app/+layout.server.ts
@@ -0,0 +1,10 @@
+import type { LayoutServerLoad } from './$types';
+import { redirect } from '@sveltejs/kit';
+
+export const load: LayoutServerLoad = async (event) => {
+ const userId = event.locals.userId ?? null;
+ if (!userId) {
+ throw redirect(303, '/');
+ }
+ return { userId };
+};
diff --git a/apps/web/src/routes/app/groups/+page.server.ts b/apps/web/src/routes/app/groups/+page.server.ts
new file mode 100644
index 0000000..4c3c1fa
--- /dev/null
+++ b/apps/web/src/routes/app/groups/+page.server.ts
@@ -0,0 +1,12 @@
+import type { PageServerLoad } from './$types';
+
+export const load: PageServerLoad = async (event) => {
+ const res = await event.fetch('/api/me/groups', { headers: { 'cache-control': 'no-store' } });
+ if (!res.ok) {
+ // El gate del layout debería impedir llegar aquí sin sesión; devolvemos vacío como salvaguarda.
+ return { groups: [] };
+ }
+ const data = await res.json();
+ const groups = Array.isArray(data?.items) ? data.items : [];
+ return { groups };
+};
diff --git a/apps/web/src/routes/app/groups/+page.svelte b/apps/web/src/routes/app/groups/+page.svelte
index c06440a..b56e13e 100644
--- a/apps/web/src/routes/app/groups/+page.svelte
+++ b/apps/web/src/routes/app/groups/+page.svelte
@@ -1,30 +1,12 @@
Cargando…
-{:else if error} -Error: {error}
-{:else if groups.length === 0} +{#if groups.length === 0}No perteneces a ningún grupo permitido.
{:else}