---
title: Implementation Roadmap
description: Low-priority features roadmap and implementation guide for future development of organization management, notifications, and other advanced features.
navigation:
  icon: i-lucide-map
---


This document outlines the remaining low-priority features and provides a step-by-step implementation guide for when you're ready to add them.

## ✅ Already Configured

### Organization/Team Plugin
- **Status**: Plugin configured in better-auth
- **Files**:
  - [app/utils/auth.ts](app/utils/auth.ts:68-90) - Server plugin
  - [app/utils/auth-client.ts](app/utils/auth-client.ts:11-28) - Client plugin
- **What's Ready**:
  - Better Auth organization plugin enabled
  - Email invitation system configured (console logging)
  - Multi-tenant database structure ready

## 📋 Implementation Steps

### 1. Team/Organization Full Implementation

#### Step 1.1: Run Database Migrations
```bash
# Better Auth will automatically create organization tables
pnpm db:generate
pnpm db:migrate
```

**Tables Created**:
- `organization` - Organization/team data
- `member` - Organization memberships
- `invitation` - Pending invitations

#### Step 1.2: Create Organization Composable
**File**: `app/composables/useOrganization.ts`

```typescript
import { authClient } from '~/utils/auth-client'

export function useOrganization() {
  const session = authClient.useSession()

  // Get user's organizations
  async function getUserOrganizations() {
    return await authClient.organization.listUserOrganizations()
  }

  // Create new organization
  async function createOrganization(name: string, slug: string) {
    return await authClient.organization.create({
      name,
      slug
    })
  }

  // Get organization members
  async function getMembers(orgId: string) {
    return await authClient.organization.listMembers({
      organizationId: orgId
    })
  }

  // Invite member
  async function inviteMember(orgId: string, email: string, role: string) {
    return await authClient.organization.inviteMember({
      organizationId: orgId,
      email,
      role
    })
  }

  // Remove member
  async function removeMember(orgId: string, userId: string) {
    return await authClient.organization.removeMember({
      organizationId: orgId,
      userId
    })
  }

  // Update member role
  async function updateMemberRole(orgId: string, userId: string, role: string) {
    return await authClient.organization.updateMemberRole({
      organizationId: orgId,
      userId,
      role
    })
  }

  // Set active organization
  async function setActiveOrganization(orgId: string) {
    return await authClient.organization.setActive({
      organizationId: orgId
    })
  }

  return {
    getUserOrganizations,
    createOrganization,
    getMembers,
    inviteMember,
    removeMember,
    updateMemberRole,
    setActiveOrganization
  }
}
```

#### Step 1.3: Create Team Pages

**Page Structure**:
```
app/pages/
├── dashboard/
│   ├── [team]/
│   │   ├── index.vue (Team dashboard)
│   │   ├── settings/
│   │   │   ├── index.vue (General settings)
│   │   │   ├── members.vue (Member management)
│   │   │   └── billing.vue (Billing - optional)
│   │   └── ...other team pages
│   └── onboard.vue (First-time team creation)
```

**Example**: `app/pages/dashboard/[team]/settings/members.vue`
```vue
<script setup lang="ts">
const route = useRoute()
const { t } = useI18n()
const { getMembers, inviteMember, removeMember, updateMemberRole } = useOrganization()

const teamSlug = computed(() => route.params.team as string)
const members = ref([])
const loading = ref(false)

// Load members
async function loadMembers() {
  loading.value = true
  const response = await getMembers(teamSlug.value)
  members.value = response.data
  loading.value = false
}

// Invite new member
const inviteEmail = ref('')
const inviteRole = ref('member')

async function handleInvite() {
  await inviteMember(teamSlug.value, inviteEmail.value, inviteRole.value)
  inviteEmail.value = ''
  await loadMembers()
}

onMounted(() => loadMembers())
</script>

<template>
  <!-- Member list and invitation UI -->
</template>
```

#### Step 1.4: Create Organization Middleware
**File**: `app/middleware/organization.global.ts`

```typescript
export default defineNuxtRouteMiddleware(async (to) => {
  // Check if route requires organization
  if (to.path.startsWith('/dashboard/') && to.params.team) {
    const { getUserOrganizations, setActiveOrganization } = useOrganization()
    const teamSlug = to.params.team as string

    // Get user's organizations
    const orgs = await getUserOrganizations()
    const org = orgs.data?.find(o => o.slug === teamSlug)

    if (!org) {
      // User doesn't have access to this organization
      return navigateTo('/dashboard')
    }

    // Set as active organization
    await setActiveOrganization(org.id)
  }
})
```

#### Step 1.5: Update Dashboard Sidebar
Add organization selector to the dashboard sidebar:

```vue
<template>
  <UDropdown :items="organizationMenuItems">
    <UButton variant="ghost">
      {{ activeOrganization?.name || 'Personal' }}
      <UIcon name="i-lucide-chevron-down" />
    </UButton>
  </UDropdown>
</template>
```

---

### 2. Login Notifications Feature

#### Step 2.1: Create Notification Schema
**File**: `server/database/schema/notifications.ts`

```typescript
import { pgTable, text, timestamp, boolean, uuid } from 'drizzle-orm/pg-core'

export const loginNotifications = pgTable('login_notifications', {
  id: uuid('id').primaryKey().defaultRandom(),
  userId: uuid('user_id').notNull().references(() => user.id, { onDelete: 'cascade' }),
  ipAddress: text('ip_address'),
  userAgent: text('user_agent'),
  location: text('location'), // City, Country
  device: text('device'), // Device type
  browser: text('browser'),
  timestamp: timestamp('timestamp').defaultNow(),
  read: boolean('read').default(false)
})
```

#### Step 2.2: Create Login Hook
**File**: `server/utils/loginHook.ts`

```typescript
// Add to better-auth config as a hook
export async function onLoginSuccess({ user, request }: { user: any, request: Request }) {
  const db = useDB()
  const ipAddress = request.headers.get('x-forwarded-for') || request.headers.get('x-real-ip')
  const userAgent = request.headers.get('user-agent')

  // Parse user agent for device/browser info
  const deviceInfo = parseUserAgent(userAgent)

  // Get location from IP (optional - use service like ipapi.co)
  const location = await getLocationFromIP(ipAddress)

  // Insert notification
  await db.insert(loginNotifications).values({
    userId: user.id,
    ipAddress,
    userAgent,
    location: location ? `${location.city}, ${location.country}` : null,
    device: deviceInfo.device,
    browser: deviceInfo.browser
  })

  // Send email notification (optional)
  // await sendLoginNotificationEmail(user.email, { location, device: deviceInfo.device })
}
```

#### Step 2.3: Create Notifications Page
**File**: `app/pages/dashboard/account/notifications.vue`

Display recent login activities with:
- Timestamp
- Location (city, country)
- Device type
- Browser
- IP address (masked)
- Mark as read functionality

---

### 3. Geographic Location Tracking

#### Step 3.1: IP Geolocation Service
Use a service like:
- **ipapi.co** (Free tier: 1,000 requests/day)
- **MaxMind GeoLite2** (Free database)
- **IPStack** (Free tier: 100 requests/month)

**Implementation**: `server/utils/geolocation.ts`

```typescript
export async function getLocationFromIP(ip: string) {
  try {
    const response = await fetch(`https://ipapi.co/${ip}/json/`)
    const data = await response.json()

    return {
      city: data.city,
      region: data.region,
      country: data.country_name,
      countryCode: data.country_code,
      latitude: data.latitude,
      longitude: data.longitude
    }
  } catch (error) {
    console.error('Failed to get location:', error)
    return null
  }
}
```

#### Step 3.2: Add to Login Notifications
Integrate with Step 2.2 above to show location in notifications.

#### Step 3.3: Security Alerts
**File**: `server/utils/securityAlerts.ts`

```typescript
export async function checkSuspiciousLogin(userId: string, newLocation: string) {
  const db = useDB()

  // Get recent logins
  const recentLogins = await db
    .select()
    .from(loginNotifications)
    .where(eq(loginNotifications.userId, userId))
    .orderBy(desc(loginNotifications.timestamp))
    .limit(5)

  // Check if location is significantly different
  const locations = recentLogins.map(l => l.location).filter(Boolean)
  const isSuspicious = locations.length > 0 && !locations.includes(newLocation)

  if (isSuspicious) {
    // Send security alert email
    // await sendSecurityAlertEmail(user.email, { newLocation, lastLocation: locations[0] })
  }

  return isSuspicious
}
```

---

### 4. Phone Number Management (Optional)

#### Step 4.1: Add Phone Number to User Schema
```typescript
// In server/database/schema/users.ts
export const user = pgTable('user', {
  // ...existing fields
  phoneNumber: text('phone_number'),
  phoneNumberVerified: boolean('phone_number_verified').default(false)
})
```

#### Step 4.2: SMS Verification
Use a service like:
- **Twilio** (Pay as you go)
- **Vonage** (Formerly Nexmo)
- **AWS SNS**

**Implementation**: Similar to email verification but with SMS

---

## 🎨 UI Components Needed

### Organization/Team Components
1. **`OrganizationSwitcher.vue`** - Dropdown to switch between organizations
2. **`MemberList.vue`** - Display organization members with roles
3. **`InviteMemberModal.vue`** - Modal to invite new members
4. **`MemberRoleSelector.vue`** - Dropdown to change member roles
5. **`OrganizationSettings.vue`** - General organization settings form

### Notification Components
1. **`LoginNotificationList.vue`** - List of recent logins
2. **`LoginNotificationCard.vue`** - Individual login notification
3. **`SecurityAlertBanner.vue`** - Banner for suspicious activities

---

## 📚 i18n Translations Needed

### Organization/Team Translations
```json
{
  "organization": {
    "title": "Organizations",
    "create": "Create Organization",
    "members": "Members",
    "inviteMember": "Invite Member",
    "roles": {
      "owner": "Owner",
      "admin": "Administrator",
      "member": "Member"
    }
  }
}
```

### Notifications Translations
```json
{
  "notifications": {
    "loginActivity": "Login Activity",
    "newLogin": "New login from {location}",
    "suspiciousLogin": "Suspicious login detected"
  }
}
```

---

## 🔐 Security Considerations

### For Organizations:
1. **Permission Checks**: Verify user has appropriate role before actions
2. **Slug Validation**: Ensure organization slugs are unique and valid
3. **Invitation Expiry**: Set expiration time for invitations (e.g., 7 days)

### For Login Notifications:
1. **IP Privacy**: Mask or partially hide IP addresses in UI
2. **Rate Limiting**: Prevent abuse of geolocation API
3. **Data Retention**: Automatically delete old notifications (e.g., after 90 days)

---

## 📊 Database Migration Commands

After implementing any of these features:

```bash
# Generate new migrations
pnpm db:generate

# Review migrations
# Check generated SQL in drizzle/migrations/

# Apply migrations
pnpm db:migrate

# Or push directly (development only)
pnpm db:push
```

---

## 🚀 Recommended Implementation Order

1. **Start with Organizations** (if multi-tenancy is crucial)
   - Most complex but provides foundation for team features
   - Requires full migration and routing changes

2. **Add Login Notifications** (easier to implement)
   - Can be added independently
   - Enhances security visibility

3. **Add Geographic Tracking** (builds on notifications)
   - Extends login notifications
   - Requires external API integration

4. **Add Phone Numbers** (optional)
   - Nice-to-have feature
   - Requires SMS service setup

---

## 💡 Quick Wins

If you want to implement something quickly:

### Quick Win #1: Basic Organization Creation
Just add ability to create organizations and store the active organization in session. No full team routing needed initially.

### Quick Win #2: Simple Login History
Show last 10 logins with timestamp only (no geolocation). Easy to implement and provides value.

### Quick Win #3: Add Organization Selector
Add a simple dropdown in the dashboard to switch between personal account and organizations (even if organizations can't be created yet).

---

## 📞 Support

- **Better Auth Docs**: https://www.better-auth.com/docs/plugins/organization
- **Discord**: Better Auth Discord community
- **GitHub**: https://github.com/better-auth/better-auth

---

## ✅ Current Status Summary

**HIGH PRIORITY**: ✅ Complete
- Email verification
- Password reset
- Password change
- Account deletion
- Separate auth pages

**MEDIUM PRIORITY**: ✅ Complete
- Magic link authentication
- Passkey/WebAuthn
- Email verification resend

**LOW PRIORITY**: 🔧 Configured, Ready for Implementation
- Organization plugin configured
- Invitation emails configured (console)
- Roadmap created for full implementation

The authentication system is now enterprise-ready with modern features. Low-priority features can be added incrementally as needed!
