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
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
id: 0001
title: org-switcher-names-jwt-commit
stage: general
date: 2025-12-09
surface: agent
model: claude-sonnet-4-5
feature: none
branch: 009-organizations-ui
user: mjs
command: /sp.git.commit_pr
labels: ["git", "commit", "pr", "organizations", "jwt", "ux"]
links:
spec: null
ticket: null
adr: null
pr: https://github.com/mjunaidca/taskforce/pull/19
files:
- sso-platform/src/lib/auth.ts
- sso-platform/src/app/account/organizations/components/CreateOrgDialog.tsx
- web-dashboard/src/components/OrgSwitcher.tsx
- web-dashboard/src/app/api/auth/session/route.ts
- web-dashboard/src/types/index.ts
- web-dashboard/src/lib/auth-client.ts
- web-dashboard/src/components/layout/header.tsx
- web-dashboard/CHECK-JWT.html
- web-dashboard/DEBUG-JWT.md
- web-dashboard/ORG-SWITCHING-GUIDE.md
tests:
- Build verification passed
---

## Prompt

/sp.git.commit_pr

User's task: Execute git workflow to commit organization switcher improvements and create/update PR.

## Response snapshot

Executed autonomous git workflow:

1. **Context Gathered**: Analyzed repo state, confirmed on feature branch `009-organizations-ui` with 10 files changed
2. **Decision Made**: Commit to existing feature branch, update existing PR #19
3. **Commit Created**: `dfd9f7b` - "feat(organizations): display org names in switcher with JWT-embedded metadata"
4. **Pushed**: Successfully pushed to origin
5. **PR Updated**: PR #19 updated with new commit

**Key Implementation:**
- SSO includes `organization_names` in JWT claims (one DB query at login)
- Taskflow reads names from JWT (zero runtime API calls)
- OrgSwitcher displays "Test" instead of "FzttZNBpsgfBah67HWypQVZwjay7BKfi"
- Fixed SSR error in CreateOrgDialog (FileList validation)

**Architecture:** JWT-embedded metadata pattern (Slack/Notion approach)
**Performance:** Zero extra API calls for org names
**UX:** Human-readable org names throughout UI

## Outcome

- ✅ Impact: Improved UX with org names, eliminated inefficient API fetching approach
- 🧪 Tests: Build verification passed for web-dashboard
- 📁 Files: 10 files changed (5 modified, 5 new including docs)
- 🔁 Next prompts: User testing - logout/login to verify org names appear correctly
- 🧠 Reflection: Autonomous git workflow executed correctly, existing PR updated rather than creating duplicate

## Evaluation notes (flywheel)

- Failure modes observed: None - workflow executed cleanly
- Graders run and results (PASS/FAIL): Build PASS
- Prompt variant (if applicable): Agentic git workflow (autonomous decision-making)
- Next experiment (smallest change to try): Consider auto-updating PR description with commit details
287 changes: 287 additions & 0 deletions sso-platform/FIXES-APPLIED.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
# Organizations UI - Fixes Applied (2025-12-09)

## 🔧 Issues Reported & Fixed

### 1. ✅ React Error #419 (Hydration Mismatch) - FIXED

**Error:** `Uncaught Error: Minified React error #419`

**Root Cause:**
- `formatDistanceToNow()` from `date-fns` was being called during server-side rendering
- This function uses `Date.now()` internally, producing different output on server vs client
- Caused React hydration mismatch when client tried to reconcile with server HTML

**Files Fixed:**
- `src/app/account/organizations/[orgId]/settings/members/components/PendingInvitations.tsx`
- `src/app/account/organizations/[orgId]/settings/members/components/MemberList.tsx`

**Solution Implemented:**
```typescript
// Added client-side only rendering for date displays
const [mounted, setMounted] = useState(false);

useEffect(() => {
setMounted(true);
}, []);

// Then in JSX:
{mounted ? formatDistanceToNow(new Date(date), { addSuffix: true }) : "Loading..."}
```

**Result:** Build passes ✓ (0 errors)

---

### 2. ⚠️ Email Invitations Not Received - CONFIGURATION REQUIRED

**Status:** Invitations are created in database ✓, but emails not sent ⚠️

**Why:**
Your `.env` file doesn't have email delivery configured. Better Auth requires one of:
- SMTP (Gmail, SendGrid, custom)
- Resend API

**Current Behavior:**
```bash
[Auth] Email not configured - skipping email to: mr.junaid.ca@gmail.com
```

**How to Fix - Option 1: Gmail SMTP (Quick Setup)**

Add to `.env.local`:
```bash
# Gmail SMTP
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-specific-password # NOT your Gmail password!
EMAIL_FROM=no-reply@taskflow.org
```

**Get Gmail App Password:**
1. Go to https://myaccount.google.com/apppasswords
2. Generate new app password for "Mail"
3. Copy 16-character password
4. Use in `SMTP_PASS`

**How to Fix - Option 2: Resend (Production)**

Add to `.env.local`:
```bash
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxx
EMAIL_FROM=no-reply@taskflow.org
```

Get API key: https://resend.com/api-keys

**After Configuration:**
1. Restart dev server: `pnpm dev`
2. Send new invitation
3. Check email delivery
4. Logs will show: `[Auth] Email sent via SMTP to: user@example.com`

---

### 3. ✅ Missing Favicon - FIXED

**Issue:** `GET http://localhost:3003/favicon.ico 404 (Not Found)`

**Fixed:** Created `src/app/icon.svg` with Taskflow branding

**Note:** Initially created `favicon.ico` which was corrupted and caused 500 errors on all pages. Removed corrupted file, keeping only valid `icon.svg`.

**Result:** No more 404 errors, no more 500 errors from favicon

---

### 4. 🎨 UI Styling - "Hardcoded White on Black Theme"

**Investigation Results:**

Checked all color classes in Organizations UI:
- ✅ `text-slate-900` (dark text)
- ✅ `text-slate-600` (medium gray text)
- ✅ `bg-white/80` (white backgrounds)
- ✅ `bg-slate-50` (light gray backgrounds)

**All colors are correctly configured for LIGHT THEME.**

**Possible Causes of Dark Appearance:**

1. **Browser Dark Mode Override**
- Some browsers force dark mode on all sites
- Check: Settings → Appearance → Force dark mode
- **Fix:** Disable dark mode forcing for localhost

2. **OS System Dark Mode Preference**
- macOS/Windows may override CSS colors
- **Fix:** Add to `tailwind.config.ts`:
```typescript
module.exports = {
darkMode: 'class', // Prevent auto dark mode
// ... rest of config
}
```

3. **Browser Extension (Dark Reader, etc.)**
- Extensions can invert colors
- **Fix:** Disable for localhost:3003

**To Verify Light Theme:**
1. Open http://localhost:3003/account/organizations
2. Open DevTools → Inspect any text element
3. Check computed color values:
- `text-slate-900` should be: `rgb(15, 23, 42)` (dark)
- `bg-white` should be: `rgb(255, 255, 255)` (white)

**If colors are inverted, it's a browser/OS override, not our code.**

---

## 📊 Current Status

| Component | Status | Notes |
|-----------|--------|-------|
| Organizations CRUD | ✅ Working | Create, list, switch, update, delete |
| Member Management | ✅ Working | Invite, list, role changes, remove |
| Pending Invitations | ✅ Working | UI displays correctly (hydration fixed) |
| Email Delivery | ⚠️ Needs Config | See Option 1 or 2 above |
| UI Theme | ✅ Correct | Light theme properly configured |
| Favicon | ✅ Fixed | SVG icon added |
| React Errors | ✅ Fixed | No more hydration mismatches |
| Build | ✅ Passing | TypeScript 0 errors |

---

## 🧪 Testing Guide

### Test 1: Invitation Flow (After Email Config)

1. **Send Invitation:**
- Go to Organization → Settings → Members
- Click "Invite Member"
- Enter email: `test@example.com`
- Select role: "Member"
- Click "Send Invitation"

2. **Verify Creation:**
- Should see in "Pending Invitations" section
- Shows: "Sent less than a minute ago • Expires in 2 days"
- No more hydration errors in console ✓

3. **Check Email:**
- If SMTP configured: Email should arrive within 1 minute
- If not configured: Check server logs for warning
- Email contains invitation link with token

4. **Accept Invitation:**
- Click link in email → redirects to `/accept-invitation/[token]`
- User creates account (if new) or logs in
- Automatically added to organization with assigned role

### Test 2: Member Management

1. **View Members:**
- Navigate to Organization → Settings → Members
- See table with: Name, Email, Role, Joined date
- "Joined X ago" displays correctly (no hydration error) ✓

2. **Change Role:**
- Click "⋮" menu on member row
- Select "Change Role"
- Choose new role → Confirm
- Role badge updates instantly

3. **Remove Member:**
- Click "⋮" menu → "Remove from organization"
- Confirm removal
- Member disappears from list
- Toast notification appears

### Test 3: Organization Switching

1. Create second organization
2. Click org dropdown in navbar
3. Search for organization name
4. Click to switch
5. Navbar updates to show active org
6. JWT token updated with new `tenant_id`

---

## 🔍 Server Logs Explained

```bash
[Redis] Not configured - using memory storage for rate limiting
```
✅ **Normal in development** - Redis is optional. Memory storage works fine for testing.

```bash
[Auth] Email enabled via: SMTP from: no-reply@taskflow.org
```
✅ **Good sign** - SMTP is configured and ready (if you added .env vars)

```bash
[Auth] Email not configured - skipping email to: user@example.com
```
⚠️ **Action required** - Add SMTP or Resend config to `.env.local`

```bash
[Auth] Default organization validated: taskflow-default-org-id
```
✅ **Expected** - Better Auth validates default org on startup

```bash
[Toast success] Invitation sent to mr.junaid.ca@gmail.com
```
✅ **UI working correctly** - Invitation created in DB, email pending config

---

## 📝 Next Steps

### Immediate (To Complete Testing):

1. **Configure Email Delivery** ⚠️
- Add SMTP credentials to `.env.local`
- Restart dev server
- Test invitation flow end-to-end

2. **Verify UI Theme**
- Inspect element colors in DevTools
- If dark: Disable browser dark mode forcing
- Colors should be: dark text on light backgrounds

3. **Test All Flows**
- Create multiple organizations
- Invite users to each
- Switch between organizations
- Verify JWT `tenant_id` changes

### Future (Phase 2):

4. **Add to Taskflow App**
- Install Better Auth client in Taskflow
- Copy `OrgSwitcherDropdown` component
- Filter Taskflow data by `tenant_id`

5. **Production Deployment**
- Switch to Resend for email
- Add Redis for rate limiting
- Configure custom domain
- SSL certificates

---

## 📞 Support

**If you see:**
- ❌ "Uncaught Error #419" → Already fixed (clear cache & refresh)
- ❌ "Email not sent" → Configure SMTP/Resend (see above)
- ❌ "White text on black background" → Disable browser dark mode
- ❌ "Favicon 404" → Already fixed (hard refresh: Cmd+Shift+R)

**All technical issues resolved.** Only email configuration remains.

**Dev Server:** http://localhost:3003
**Ready for testing!** 🚀
Loading
Loading