Files
GearBox/.planning/milestones/v2.2-phases/28-profile-and-logto-integration/28-03-PLAN.md
Jean-Luc Makiola 2853477a75
All checks were successful
CI / ci (push) Successful in 1m15s
CI / e2e (push) Has been skipped
CI / deploy (push) Has been skipped
chore: archive v2.2 User Experience Polish milestone
Phases 28-31 archived to milestones/v2.2-phases/
Requirements and roadmap snapshots archived to milestones/

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:00:35 +02:00

10 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, user_setup, must_haves
phase plan type wave depends_on files_modified autonomous requirements user_setup must_haves
28-profile-and-logto-integration 03 execute 2
01
02
src/client/routes/__root.tsx
src/server/routes/auth.ts
false
type name instructions
external_config Logto Sign-In Branding In Logto Console > Sign-in & account > Branding: 1. Upload GearBox logo (dark variant for light backgrounds) 2. Set brand color to #374151 (gray-700) 3. Add custom CSS to match GearBox styling (rounded corners, font, button styles) 4. Use CSS attribute selectors: div[class$=container], button[class$=button]
type name instructions
external_config Logto Social Connectors (D-09) In Logto Console > Connectors > Social connectors: 1. Add Google connector — requires Google Cloud Console OAuth 2.0 credentials 2. Add GitHub connector — requires GitHub Developer Settings OAuth App 3. Enable both in Sign-in & account > Sign-up & sign-in > Social sign-in
type name instructions
external_config Logto Email Verification (D-10) In Logto Console > Sign-in & account > Sign-up & sign-in: - Require email verification at signup
type name instructions
external_config Logto Password Policy (D-11) In Logto Console > Sign-in & account > Password policy: - Minimum length: 8 - Require: uppercase, lowercase, number
type name instructions
external_config Custom Domain (D-08, optional) Configure reverse proxy (nginx/Caddy) to serve Logto under auth.gearbox.de. Update OIDC_ISSUER env var to https://auth.gearbox.de/oidc. Update OIDC_REDIRECT_URI to use the new domain.
truths artifacts key_links
Navigation includes link to /profile page
/me endpoint returns createdAt field for member-since display
Logto sign-in page shows GearBox branding (manual verification)
Google and GitHub social sign-in connectors are enabled (manual verification)
Email verification is required at signup (manual verification)
src/client/routes/__root.tsx (updated with profile nav link)
src/server/routes/auth.ts (updated /me endpoint)
Navigation profile link points to /profile route from Plan 02
/me endpoint provides createdAt used by profile page account info section
Wire navigation to /profile, extend /me endpoint with member-since data, and configure Logto branding/social connectors/policies per D-07, D-08, D-09, D-10, D-11.

Purpose: Make the profile page discoverable via navigation, provide the createdAt data needed by the profile page, and ensure Logto is configured with GearBox branding and security policies so users never feel they've left the app (D-07). Output: Updated navigation, extended /me endpoint, Logto configuration checkpoints

<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/28-profile-and-logto-integration/28-CONTEXT.md @.planning/phases/28-profile-and-logto-integration/28-RESEARCH.md

@src/client/routes/__root.tsx @src/server/routes/auth.ts @src/client/hooks/useAuth.ts

<threat_model>

Threat Model

ID Threat Severity Mitigation
T-28-10 createdAt leaks information about user registration patterns LOW Only return for authenticated user's own data (already behind /me auth)
</threat_model>
Task 1: Add profile navigation link and extend /me endpoint src/client/routes/__root.tsx, src/server/routes/auth.ts, src/client/hooks/useAuth.ts - src/client/routes/__root.tsx (current navigation layout — find where settings/logout links are) - src/server/routes/auth.ts (current /me endpoint — see what it returns) - src/client/hooks/useAuth.ts (AuthState interface — needs createdAt field) - src/db/schema.ts (users table — createdAt column) **Update `src/server/routes/auth.ts` — extend /me endpoint:**

In the GET /me handler, after getOrCreateUser(db, auth.sub), also query the full user record to get createdAt:

app.get("/me", async (c) => {
  const auth = await getAuth(c);
  if (auth) {
    const db = c.get("db");
    const user = await getOrCreateUser(db, auth.sub);
    // Get full user record for createdAt
    const [fullUser] = await db.select().from(users).where(eq(users.id, user.id));
    return c.json({
      user: {
        id: user.id,
        email: auth.email,
        createdAt: fullUser?.createdAt?.toISOString() ?? null,
      },
      authenticated: true,
    });
  }
  return c.json({ user: null, authenticated: false });
});

Add necessary imports: import { eq } from "drizzle-orm" and import { users } from "../../db/schema.ts".

Update src/client/hooks/useAuth.ts — extend AuthState interface:

Add createdAt to the user type:

interface AuthState {
  user: { id: string; email?: string; createdAt?: string } | null;
  authenticated: boolean;
}

Update src/client/routes/__root.tsx — add profile link:

Find the navigation section where settings/logout links exist (look for /settings or useLogout). Add a "Profile" link next to or near the settings link:

<Link to="/profile" className="...">Profile</Link>

Use the same styling as the existing settings link. If the nav uses icons, use the "User" or "CircleUser" icon from the curated Lucide icon set (check lib/iconData for available icons). If no icon-based nav, use text link.

Only show the Profile link when auth?.authenticated is true (same guard as existing settings/logout links). <acceptance_criteria> - src/server/routes/auth.ts /me endpoint response includes createdAt field - src/server/routes/auth.ts imports users from schema and eq from drizzle-orm - src/client/hooks/useAuth.ts AuthState interface includes createdAt?: string - src/client/routes/__root.tsx contains a Link to /profile - The profile link is only visible when authenticated </acceptance_criteria> grep -q "createdAt" src/server/routes/auth.ts && grep -q "createdAt" src/client/hooks/useAuth.ts && grep -q "/profile" src/client/routes/__root.tsx /me returns createdAt, AuthState type includes it, navigation has profile link visible to authenticated users

Task 2: Configure Logto branding, social connectors, and security policies NONE (Logto Console configuration only) - .planning/phases/28-profile-and-logto-integration/28-RESEARCH.md (section 6 — branding details) - .planning/phases/28-profile-and-logto-integration/28-CONTEXT.md (D-07, D-08, D-09, D-10, D-11) This task requires manual configuration in the Logto admin console. Claude cannot perform these actions.

D-07: Sign-in page branding — In Logto Console > Sign-in & account > Branding:

  1. Upload GearBox logo (PNG/SVG, dark version for white background)
  2. Set brand color to #374151 (gray-700)
  3. Add custom CSS to match GearBox styling. Key selectors:
    • div[class$=container] — set font-family to match system font stack
    • button[class$=primary] — set background-color: #374151, border-radius: 0.5rem
    • input[class$=input] — set border-color: #e5e7eb (gray-200), border-radius: 0.5rem
  4. Verify by visiting /login — page should feel like GearBox, not generic Logto

D-08: Custom domain (optional, if DNS supports it):

  1. Configure reverse proxy to serve Logto under auth.gearbox.de
  2. Update OIDC_ISSUER env var to https://auth.gearbox.de/oidc
  3. Update OIDC_REDIRECT_URI to use the custom domain

D-09: Social connectors — In Logto Console > Connectors > Social:

  1. Google: Create OAuth 2.0 credentials in Google Cloud Console. Configure Google connector in Logto with client ID and secret.
  2. GitHub: Create OAuth App in GitHub Developer Settings. Configure GitHub connector in Logto with client ID and secret.
  3. Enable both in Sign-in & account > Sign-up & sign-in > Social sign-in section.

D-10: Email verification — In Logto Console > Sign-in & account > Sign-up & sign-in:

  • Set email verification to "Required" for new signups

D-11: Password policy — In Logto Console > Sign-in & account > Password policy:

  • Minimum length: 8
  • Require: uppercase letter
  • Require: lowercase letter
  • Require: number <acceptance_criteria>
    • Visiting /login shows GearBox-branded login page (logo, colors)
    • Google and GitHub social sign-in buttons appear on the login page
    • Creating a new account requires email verification
    • Attempting to set a password shorter than 8 chars or without mixed case is rejected </acceptance_criteria> echo "Manual verification required — Logto Console configuration" Logto sign-in page shows GearBox branding with logo and matching colors, Google and GitHub social sign-in are available, email verification is required, password policy enforces 8+ chars with mixed case and number
1. `bun run lint` — no lint errors 2. `bun run build` — build succeeds 3. Navigation shows profile link when authenticated 4. /me endpoint returns createdAt in response 5. Manual: Logto login page shows GearBox branding 6. Manual: Social sign-in buttons visible

<success_criteria>

  • Profile page is discoverable via navigation
  • /me endpoint provides createdAt for member-since display
  • Logto sign-in page is branded to match GearBox (D-07)
  • Google and GitHub social connectors are configured (D-09)
  • Email verification required at signup (D-10)
  • Password policy enforces strength requirements (D-11) </success_criteria>