fix: update documentation and configuration files

This commit is contained in:
2026-03-29 19:26:50 -07:00
parent 00aa8cf044
commit 26d9c7e79e
50 changed files with 6264 additions and 2627 deletions
+239 -151
View File
@@ -1,73 +1,95 @@
# Authentication, Authorization, and Accounting (AAA) Design
## Overview
Implement a comprehensive AAA system for EuchreCamp with user authentication, role-based authorization, and activity logging.
Implement a comprehensive AAA system for EuchreCamp with user authentication, role-based authorization, and activity logging using Next.js and Better Auth.
## Authentication (Who are you?)
### User Model
```ruby
# Database Schema
table :users do
primary_key :id
foreign_key :player_id, :players # Links to existing player record
column :email, String, null: false, unique: true
column :password_digest, String, null: false
column :confirmed, Boolean, default: false
column :confirmation_token, String
column :confirmation_sent_at, DateTime
column :reset_password_token, String
column :reset_password_sent_at, DateTime
column :failed_login_attempts, Integer, default: 0
column :locked_until, DateTime
column :last_login_at, DateTime
column :last_login_ip, String
column :created_at, DateTime, null: false
column :updated_at, DateTime, null: false
end
### User Model (Prisma Schema)
# Indexes
add_index :users, :email, unique: true
add_index :users, :confirmation_token
add_index :users, :reset_password_token
```prisma
// prisma/schema.prisma
model User {
id String @id @default(cuid())
email String @unique
emailVerified Boolean @default(false)
password String?
name String?
role Role @default(PLAYER)
// Relationships
player Player? @relation(fields: [playerId], references: [id])
playerId String?
// Better Auth fields
accounts Account[]
sessions Session[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Player {
id String @id @default(cuid())
name String
rating Int @default(1000)
user User?
userId String?
// Relationships
matches Match[]
partnerships Partnership[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
enum Role {
PLAYER
TOURNAMENT_ADMIN
CLUB_ADMIN
}
```
### Authentication Flow
1. User enters email and password
2. System verifies email exists and account is not locked
3. BCrypt verifies password hash
4. If successful:
- Update `last_login_at` and `last_login_ip`
- Reset `failed_login_attempts`
- Create session/token
5. If failed:
- Increment `failed_login_attempts`
- Lock account after 5 failed attempts (15 minutes)
### Authentication Flow (Better Auth)
### Session Management
- Use signed cookies for session storage
- Session expires after 30 days of inactivity
- Session invalidation on password change
- Concurrent session limits (optional)
1. User enters email and password
2. Better Auth verifies email exists
3. Password verification using secure hashing (scrypt by default)
4. If successful:
- Create session token
- Set secure HTTP-only cookie
- Redirect to dashboard
5. If failed:
- Rate limiting applied (Better Auth built-in)
- Account lockout after multiple failed attempts
### Session Management (Better Auth)
- **Session Storage**: Secure HTTP-only cookies
- **Session Expiration**: Configurable (default 30 days)
- **Session Invalidation**: On password change
- **Concurrent Sessions**: Supported with session tracking
### Password Requirements
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- At least one special character
### Registration Flow
1. User registers with email and password
2. System creates user record with `confirmed: false`
3. Send confirmation email with unique token
4. User clicks link to confirm account
5. Account activated and ready for login
- Minimum 8 characters
- Configurable via Better Auth settings
- Hashed with scrypt (server-side)
### Registration Flow (Next.js + Better Auth)
1. User registers with email and password via `/auth/register`
2. System creates user record with `emailVerified: false`
3. Email confirmation flow (if enabled)
4. User can log in after verification
### Password Reset Flow
1. User requests password reset
2. System generates unique token (expires in 1 hour)
3. Send reset email with token link
1. User requests password reset via `/auth/reset-password`
2. System generates unique token
3. Email reset link to user
4. User enters new password
5. System validates and updates password hash
6. Invalidate all existing sessions
@@ -77,85 +99,124 @@ add_index :users, :reset_password_token
### Role-Based Access Control (RBAC)
#### Roles
```ruby
ROLES = {
player: 0, # Default user - can view rankings, own profile
tournament_admin: 1, # Can manage specific tournaments
club_admin: 2, # Superuser - full access
system_admin: 3 # Technical admin access
```typescript
// src/lib/auth.ts
enum Role {
PLAYER = 0, // Default user - can view rankings, own profile
TOURNAMENT_ADMIN = 1, // Can manage specific tournaments
CLUB_ADMIN = 2 // Superuser - full access
}
```
#### Permission Matrix
| Permission | Player | Tournament Admin | Club Admin | System Admin |
|------------|--------|------------------|------------|--------------|
| View rankings | ✅ | ✅ | ✅ | ✅ |
| View own profile | ✅ | ✅ | ✅ | ✅ |
| Edit own profile | ✅ | ✅ | ✅ | ✅ |
| View other profiles | ✅ | ✅ | ✅ | ✅ |
| Record own matches | ✅ | ✅ | ✅ | ✅ |
| Create tournaments | ❌ | ✅ | ✅ | ✅ |
| Manage own tournaments | ❌ | ✅ | ✅ | ✅ |
| Manage all tournaments | ❌ | ❌ | ✅ | ✅ |
| Manage all players | ❌ | ❌ | ✅ | ✅ |
| Club settings | ❌ | ❌ | ✅ | ✅ |
| System settings | ❌ | ❌ | ❌ | ✅ |
| Permission | Player | Tournament Admin | Club Admin |
|------------|--------|------------------|------------|
| View rankings | ✅ | ✅ | ✅ |
| View own profile | ✅ | ✅ | ✅ |
| Edit own profile | ✅ | ✅ | ✅ |
| View other profiles | ✅ | ✅ | ✅ |
| Record own matches | ✅ | ✅ | ✅ |
| Create tournaments | ❌ | ✅ | ✅ |
| Manage own tournaments | ❌ | ✅ | ✅ |
| Manage all tournaments | ❌ | ❌ | ✅ |
| Manage all players | ❌ | ❌ | ✅ |
| Club settings | ❌ | ❌ | ✅ |
### Implementation
```ruby
module EuchreCamp
module Auth
class Authorization
def self.can?(user, action, resource = nil)
case action
when :view_rankings
true # All users can view rankings
when :edit_profile
resource.nil? || resource.id == user.player_id
when :create_tournament
user.club_admin? || user.system_admin?
when :manage_tournament
user.club_admin? || user.system_admin? ||
(user.tournament_admin? && resource.admin_id == user.player_id)
when :manage_players
user.club_admin? || user.system_admin?
else
false
end
end
end
end
end
```typescript
// src/lib/auth.ts
import { betterAuth } from "better-auth";
import { prisma } from "./prisma";
export const auth = betterAuth({
database: prisma,
emailAndPassword: {
enabled: true,
},
plugins: [
// Additional plugins as needed
],
});
// Authorization helper
export function can(user: User, action: string, resource?: any): boolean {
switch (action) {
case "view_rankings":
return true; // All users can view rankings
case "edit_profile":
return !resource || resource.id === user.playerId;
case "create_tournament":
return user.role === "CLUB_ADMIN";
case "manage_tournament":
return user.role === "CLUB_ADMIN" ||
(user.role === "TOURNAMENT_ADMIN" && resource.adminId === user.playerId);
case "manage_players":
return user.role === "CLUB_ADMIN";
default:
return false;
}
}
```
### Middleware
- Authentication middleware checks for valid session
- Authorization middleware verifies permissions
- Redirect unauthenticated users to login
- Show 403 Forbidden for unauthorized actions
```typescript
// src/middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { getSession } from "@/lib/auth";
export async function middleware(request: NextRequest) {
const session = await getSession(request);
// Protect admin routes
if (request.nextUrl.pathname.startsWith("/admin")) {
if (!session) {
return NextResponse.redirect(new URL("/auth/login", request.url));
}
if (session.user.role !== "CLUB_ADMIN") {
return NextResponse.redirect(new URL("/unauthorized", request.url));
}
}
return NextResponse.next();
}
export const config = {
matcher: ["/admin/:path*"],
};
```
## Accounting (What did you do?)
### Activity Logging
```ruby
table :activity_logs do
primary_key :id
foreign_key :user_id, :users
column :action, String, null: false # e.g., 'login', 'create_tournament', 'record_match'
column :resource_type, String # e.g., 'tournament', 'match', 'player'
column :resource_id, Integer
column :ip_address, String
column :user_agent, String
column :details, JSON # Additional context
column :created_at, DateTime, null: false
end
### Activity Logging (Prisma)
add_index :activity_logs, [:user_id, :created_at]
add_index :activity_logs, [:resource_type, :resource_id]
```prisma
// prisma/schema.prisma
model ActivityLog {
id String @id @default(cuid())
userId String
action String // e.g., 'login', 'create_tournament', 'record_match'
resourceType String? // e.g., 'tournament', 'match', 'player'
resourceId String?
ipAddress String?
userAgent String?
details Json? // Additional context
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
@@index([userId, createdAt])
@@index([resourceType, resourceId])
}
```
### Tracked Events
- Authentication events (login, logout, password change)
- Tournament management (create, update, delete, schedule)
- Match recording (create, update, delete)
@@ -163,27 +224,56 @@ add_index :activity_logs, [:resource_type, :resource_id]
- Settings changes
### Audit Reports
- User activity timeline
- Tournament lifecycle audit
- Match result verification log
- System changes overview
### Implementation
```typescript
// src/lib/activity.ts
import { prisma } from "./prisma";
export async function logActivity(
userId: string,
action: string,
resourceType?: string,
resourceId?: string,
details?: any
) {
await prisma.activityLog.create({
data: {
userId,
action,
resourceType,
resourceId,
details,
ipAddress: "0.0.0.0", // Get from request
userAgent: "unknown", // Get from request
},
});
}
```
## Implementation Plan
### Phase 1: Authentication (Week 1-2)
- [ ] Create users table and model
- [ ] Implement BCrypt password hashing
- [ ] Build login/logout actions
- [ ] Create registration flow
- [ ] Add session management
- [x] Set up Better Auth with Prisma
- [x] Create login page (`/auth/login`)
- [x] Create registration page (`/auth/register`)
- [x] Implement session management
- [x] Add navigation for logged-in users
- [ ] Password reset functionality
- [ ] Email confirmation system
### Phase 2: Authorization (Week 2-3)
- [ ] Define roles and permissions
- [ ] Implement RBAC middleware
- [x] Define roles in Prisma schema
- [x] Implement RBAC middleware
- [ ] Add role assignment UI (for club admins)
- [ ] Protect routes based on roles
- [ ] Add permission checks to actions
- [ ] Add permission checks to API routes
### Phase 3: Accounting (Week 3-4)
- [ ] Create activity logging system
@@ -192,19 +282,19 @@ add_index :activity_logs, [:resource_type, :resource_id]
- [ ] Add activity feed to dashboard
### Phase 4: Security Hardening (Week 4-5)
- [ ] Rate limiting on login attempts
- [x] Rate limiting (Better Auth built-in)
- [ ] IP-based lockout
- [ ] Secure cookie settings
- [ ] CSRF protection
- [ ] CSRF protection (Next.js built-in)
- [ ] Security headers
- [ ] Session fixation prevention
## Security Considerations
### Password Security
- Use BCrypt with cost factor 12+
- Use scrypt hashing (Better Auth default)
- Never store plaintext passwords
- Enforce strong password policy
- Enforce strong password policy (via Better Auth)
- Rate limit password attempts
### Session Security
@@ -220,40 +310,38 @@ add_index :activity_logs, [:resource_type, :resource_id]
- Log all access attempts
### Data Protection
- Encrypt sensitive data at rest
- Secure transmission (HTTPS only)
- Regular security audits
- Compliance with privacy regulations
## API Endpoints
### Authentication
### Authentication (Better Auth)
```
POST /auth/login # Login with email/password
POST /auth/logout # Logout current session
POST /auth/register # Create new account
POST /auth/confirm # Confirm email address
POST /auth/forgot # Request password reset
POST /auth/reset # Reset password with token
POST /api/auth/sign-up/email # Register new account
POST /api/auth/sign-in/email # Login with email/password
POST /api/auth/sign-out # Logout current session
POST /api/auth/forgot-password # Request password reset
POST /api/auth/reset-password # Reset password with token
```
### Users
```
GET /users/me # Get current user profile
PATCH /users/me # Update own profile
GET /users/:id # Get user profile (public)
GET /api/users/me # Get current user profile
PATCH /api/users/me # Update own profile
GET /api/users/:id # Get user profile (public)
```
### Admin
```
GET /admin/users # List users (club admin only)
PATCH /admin/users/:id # Update user roles (club admin only)
GET /admin/activity # View audit logs (club admin only)
GET /api/admin/users # List users (club admin only)
PATCH /api/admin/users/:id # Update user roles (club admin only)
GET /api/admin/activity # View audit logs (club admin only)
```
## Testing Strategy
### Unit Tests
### Unit Tests (Vitest)
- Password hashing verification
- Permission calculations
- Session management
@@ -266,18 +354,18 @@ GET /admin/activity # View audit logs (club admin only)
- Role-based access
### Security Tests
- SQL injection prevention
- XSS prevention
- CSRF protection
- SQL injection prevention (Prisma)
- XSS prevention (Next.js)
- CSRF protection (Next.js)
- Rate limiting
- Session security
## Migration Steps
1. Create users table and related migrations
2. Add foreign key from users to players
3. Migrate existing player data to users (optional)
1. Set up Better Auth with Prisma
2. Create users table and related models
3. Add foreign key from users to players
4. Update navigation to show login/logout links
5. Add authentication checks to existing actions
5. Add authentication checks to existing routes
6. Implement role assignment for existing admins
7. Set up activity logging for new features