Merge branch 'main' of https://code.hal9000.damnserver.com/MasterMito/work-club-manager
CI Pipeline / Backend Build & Test (push) Successful in 54s
CI Pipeline / Frontend Lint, Test & Build (push) Successful in 31s
CI Pipeline / Infrastructure Validation (push) Successful in 3s

This commit is contained in:
WorkClub Automation
2026-03-20 13:31:42 +01:00
37 changed files with 4387 additions and 203 deletions
@@ -67,9 +67,9 @@ export default function ShiftDetailPage({ params }: { params: Promise<{ id: stri
<p className="text-sm text-muted-foreground">No sign-ups yet</p>
) : (
<ul className="list-disc list-inside text-sm">
{shift.signups.map((signup) => (
<li key={signup.id}>Member ID: {signup.memberId}</li>
))}
{shift.signups.map((signup) => (
<li key={signup.id}>{signup.memberName || signup.memberId}</li>
))}
</ul>
)}
</div>
@@ -85,11 +85,11 @@ export default function TaskDetailPage({ params }: { params: Promise<{ id: strin
<div className="grid grid-cols-2 gap-4">
<div>
<p className="text-sm font-medium text-muted-foreground">Assignee</p>
<p className="mt-1">{task.assigneeId || 'Unassigned'}</p>
<p className="mt-1">{task.assigneeName || 'Unassigned'}</p>
</div>
<div>
<p className="text-sm font-medium text-muted-foreground">Created By</p>
<p className="mt-1">{task.createdById}</p>
<p className="mt-1">{task.createdByName || task.createdById}</p>
</div>
<div>
<p className="text-sm font-medium text-muted-foreground">Created At</p>
+1 -1
View File
@@ -89,7 +89,7 @@ export default function TaskListPage() {
{task.status}
</Badge>
</TableCell>
<TableCell>{task.assigneeId || 'Unassigned'}</TableCell>
<TableCell>{task.assigneeName || 'Unassigned'}</TableCell>
<TableCell>{new Date(task.createdAt).toLocaleDateString()}</TableCell>
<TableCell className="text-right">
<Button variant="outline" size="sm" asChild>
+26 -4
View File
@@ -24,16 +24,15 @@ declare module "next-auth" {
// In Docker, the Next.js server reaches Keycloak via internal hostname
// (keycloak:8080) but the browser uses localhost:8080. Explicit endpoint
// URLs bypass OIDC discovery, avoiding issuer mismatch validation errors.
const issuerPublic = process.env.KEYCLOAK_ISSUER!
const issuerPublic = process.env.KEYCLOAK_ISSUER || 'http://localhost:8080/realms/workclub'
const issuerInternal = process.env.KEYCLOAK_ISSUER_INTERNAL || issuerPublic
const oidcPublic = `${issuerPublic}/protocol/openid-connect`
const oidcInternal = `${issuerInternal}/protocol/openid-connect`
const oidcInternal = `${issuerInternal.replace(':8080', ':8081')}/protocol/openid-connect`
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_CLIENT_ID!,
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET!,
clientId: process.env.KEYCLOAK_CLIENT_ID || 'workclub-app',
issuer: issuerPublic,
authorization: {
url: `${oidcPublic}/auth`,
@@ -41,8 +40,31 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
},
token: `${oidcInternal}/token`,
userinfo: `${oidcInternal}/userinfo`,
jwks_endpoint: `${oidcInternal}/certs`,
})
],
trustHost: true,
cookies: {
pkceCodeVerifier: {
name: "authjs.pkce.code_verifier",
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
secure: false,
},
},
state: {
name: "authjs.state",
options: {
httpOnly: true,
sameSite: "lax",
path: "/",
secure: false,
},
},
},
debug: true,
callbacks: {
async jwt({ token, account }) {
if (account && account.access_token) {
+1
View File
@@ -38,6 +38,7 @@ export interface ShiftDetailDto {
export interface ShiftSignupDto {
id: string;
memberId: string;
memberName?: string;
externalUserId?: string;
signedUpAt: string;
}
+3
View File
@@ -14,6 +14,7 @@ export interface TaskListItemDto {
title: string;
status: string;
assigneeId: string | null;
assigneeName?: string;
createdAt: string;
isAssignedToMe: boolean;
}
@@ -24,7 +25,9 @@ export interface TaskDetailDto {
description: string | null;
status: string;
assigneeId: string | null;
assigneeName?: string;
createdById: string;
createdByName?: string;
clubId: string;
dueDate: string | null;
createdAt: string;