feat: set up authentication infrastructure with NextAuth.js v5

- Install next-auth@beta, bcryptjs, zod, and @auth/prisma-adapter
- Create auth.ts with credentials provider and JWT session strategy
- Create auth.config.ts for edge-compatible middleware configuration
- Add NextAuth type extensions for session and JWT
- Create API route handler for authentication
- Configure environment variables for NextAuth
- Add AUTH_SETUP.md documentation

Task: 1. Set up authentication infrastructure
Requirements: 1.1, 2.1
This commit is contained in:
2025-12-01 23:56:45 +00:00
parent b3c7f92877
commit 2c3b66b085
12 changed files with 1602 additions and 3 deletions

9
.env.example Normal file
View File

@@ -0,0 +1,9 @@
DATABASE_URL="mysql://user:password@host:port/database"
# NextAuth Configuration
# NEXTAUTH_URL should be your production URL in production
NEXTAUTH_URL=http://localhost:3000
# Generate a secure secret with: openssl rand -base64 32
NEXTAUTH_SECRET=your-secret-key-here-please-change-in-production
AUTH_SECRET=your-secret-key-here-please-change-in-production

View File

@@ -223,7 +223,7 @@
- Use React.memo for expensive components - Use React.memo for expensive components
- _Requirements: All (performance is cross-cutting)_ - _Requirements: All (performance is cross-cutting)_
- [-] 19. Final checkpoint - Ensure all tests pass - [x] 19. Final checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise. - Ensure all tests pass, ask the user if questions arise.
- [ ] 20. End-to-end testing and polish - [ ] 20. End-to-end testing and polish

View File

@@ -0,0 +1,745 @@
# Design Document: User Authentication and Sharing
## Overview
This design extends the Ultimate Lists App to support multi-user authentication and collaborative list sharing. The system will implement secure user registration and login using NextAuth.js (Auth.js v5), session management with JWT tokens, and a permission-based access control system for list sharing.
The authentication system integrates seamlessly with the existing Next.js 14 App Router architecture, using Server Actions for authentication operations and middleware for route protection. The design maintains the current PWA capabilities while adding user-specific data isolation and collaborative features.
Key design decisions:
- **NextAuth.js v5** for authentication (industry-standard, well-maintained, Next.js 14 compatible)
- **Credentials provider** for email/password authentication
- **bcrypt** for password hashing
- **JWT sessions** for stateless authentication
- **Middleware-based route protection** for securing pages
- **Permission-based access control** with owner, editor, and viewer roles
- **Database-level access control** to ensure data isolation
## Architecture
### High-Level Architecture
```
┌─────────────────────────────────────────────────────────┐
│ Client Browser │
│ ┌──────────────────────────────────────────────────┐ │
│ │ React Components (RSC + Client) │ │
│ │ ┌────────────┐ ┌────────────┐ ┌───────────┐ │ │
│ │ │Auth Pages │ │ Components │ │ Hooks │ │ │
│ │ │Login/ │ │ (Protected)│ │ │ │ │
│ │ │Register │ │ │ │ │ │ │
│ │ └────────────┘ └────────────┘ └───────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Service Worker (PWA) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ HTTP/Server Actions
▼
┌─────────────────────────────────────────────────────────┐
│ Next.js Server │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Middleware │ │
│ │ (Route Protection & Auth) │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ NextAuth.js │ │
│ │ (Session Management & Authentication) │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Server Actions │ │
│ │ (Business Logic + Access Control) │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Prisma Client │ │
│ │ (Data Access with ACL) │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
│
│ SQL
▼
┌─────────────────────────────────────────────────────────┐
│ MySQL Database │
│ (Users, Lists, Items, Collaborators, Invitations) │
└─────────────────────────────────────────────────────────┘
```
### Technology Stack
**New Dependencies:**
- **next-auth@5.0.0-beta**: Authentication framework for Next.js
- **bcryptjs**: Password hashing library
- **@types/bcryptjs**: TypeScript types for bcryptjs
- **zod**: Schema validation for forms and API inputs
**Existing Stack:**
- Framework: Next.js 14 with App Router
- Language: TypeScript
- Database: MySQL with Prisma ORM
- UI: React 18 with Tailwind CSS
## Components and Interfaces
### Authentication Layer
**NextAuth Configuration (`auth.ts`)**
```typescript
// Core authentication configuration
export const authOptions = {
providers: [
CredentialsProvider({
credentials: { email, password },
authorize: async (credentials) => {
// Validate credentials
// Query user from database
// Verify password with bcrypt
// Return user object or null
}
})
],
session: { strategy: 'jwt' },
callbacks: {
jwt: async ({ token, user }) => {
// Add user ID to token
},
session: async ({ session, token }) => {
// Add user ID to session
}
},
pages: {
signIn: '/auth/login',
signOut: '/auth/logout',
error: '/auth/error'
}
}
```
**Middleware (`middleware.ts`)**
```typescript
// Protect routes requiring authentication
export function middleware(request: NextRequest) {
// Check authentication status
// Redirect to login if not authenticated
// Allow access if authenticated
}
export const config = {
matcher: ['/', '/list/:path*', '/profile/:path*']
}
```
**Authentication Actions (`lib/auth-actions.ts`)**
- `registerUser(email, password, name)`: Create new user account
- `validateCredentials(email, password)`: Verify login credentials
- `updatePassword(userId, currentPassword, newPassword)`: Change password
- `updateProfile(userId, data)`: Update user profile
- `deleteAccount(userId)`: Delete user and associated data
### Access Control Layer
**Permission Utilities (`lib/permissions.ts`)**
```typescript
type Permission = 'owner' | 'editor' | 'viewer'
// Check if user can access list
async function canAccessList(userId: string, listId: string): Promise<boolean>
// Check if user can edit list
async function canEditList(userId: string, listId: string): Promise<boolean>
// Check if user can delete list
async function canDeleteList(userId: string, listId: string): Promise<boolean>
// Get user's permission level for list
async function getPermission(userId: string, listId: string): Promise<Permission | null>
```
**Modified Server Actions (`lib/actions.ts`)**
All existing server actions will be modified to include access control:
- `getLists(userId)`: Get lists user owns or has access to
- `createList(userId, title, color)`: Create list owned by user
- `updateList(userId, listId, data)`: Update list if user has permission
- `deleteList(userId, listId)`: Delete list if user is owner
- `getListWithItems(userId, listId)`: Get list if user has access
- `createItem(userId, listId, data)`: Create item if user can edit
- `updateItem(userId, itemId, data)`: Update item if user can edit parent list
- `deleteItem(userId, itemId)`: Delete item if user can edit parent list
- `toggleItem(userId, itemId)`: Toggle item if user can edit parent list
**Sharing Actions (`lib/sharing-actions.ts`)**
- `inviteUserToList(ownerId, listId, email, permission)`: Create invitation
- `getInvitations(userId)`: Get pending invitations for user
- `acceptInvitation(userId, invitationId)`: Accept invitation and grant access
- `declineInvitation(userId, invitationId)`: Decline and remove invitation
- `getCollaborators(userId, listId)`: Get users with access to list
- `updateCollaboratorPermission(ownerId, listId, collaboratorId, permission)`: Change permission level
- `removeCollaborator(ownerId, listId, collaboratorId)`: Revoke access
### Presentation Layer
**New Pages**
- `/auth/login` - Login form
- `/auth/register` - Registration form
- `/auth/error` - Authentication error display
- `/profile` - User profile management
- `/invitations` - Pending invitations list
**New Components**
- `LoginForm`: Email/password login form with validation
- `RegisterForm`: Registration form with password requirements
- `ProfileForm`: Edit user profile information
- `PasswordChangeForm`: Change password with current password verification
- `InvitationCard`: Display invitation with accept/decline actions
- `CollaboratorList`: Show users with access to a list
- `ShareListModal`: Invite users to a list
- `PermissionBadge`: Display permission level (owner/editor/viewer)
- `ProtectedRoute`: Wrapper component for authenticated routes
**Modified Components**
- `ListCard`: Show sharing indicator if list has collaborators
- `ListDetailView`: Add share button for owners, show permission level
- `ItemForm`: Disable editing for viewers
## Data Models
### New Database Models
**User Model**
```typescript
{
id: string (cuid)
email: string (unique)
name: string | null
passwordHash: string
createdAt: DateTime
updatedAt: DateTime
ownedLists: List[] (relation)
collaborations: Collaborator[] (relation)
sentInvitations: Invitation[] (relation)
receivedInvitations: Invitation[] (relation)
}
```
**Collaborator Model** (Join table for list sharing)
```typescript
{
id: string (cuid)
userId: string
listId: string
permission: 'editor' | 'viewer'
createdAt: DateTime
user: User (relation)
list: List (relation)
@@unique([userId, listId])
}
```
**Invitation Model**
```typescript
{
id: string (cuid)
email: string
listId: string
inviterId: string
permission: 'editor' | 'viewer'
status: 'pending' | 'accepted' | 'declined'
createdAt: DateTime
expiresAt: DateTime
list: List (relation)
inviter: User (relation)
}
```
### Modified Database Models
**List Model** (add owner relationship)
```typescript
{
id: string (cuid)
title: string
color: string
ownerId: string (new)
createdAt: DateTime
updatedAt: DateTime
owner: User (new relation)
items: Item[]
collaborators: Collaborator[] (new relation)
invitations: Invitation[] (new relation)
}
```
**Item Model** (no changes to schema, but queries will check list access)
```typescript
{
// Existing fields remain the same
// Access control enforced through parent list
}
```
### Session Model
**Session Data** (stored in JWT)
```typescript
{
user: {
id: string
email: string
name: string | null
}
expires: string (ISO date)
}
```
## Correctness Properties
*A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
### User Registration Properties
**Property 1: Registration creates unique user**
*For any* valid email and password, registering a new user should create a user account with a unique identifier that differs from all existing user identifiers.
**Validates: Requirements 1.1**
**Property 2: Duplicate email rejection**
*For any* existing user email, attempting to register with that email should be rejected and return an error.
**Validates: Requirements 1.2**
**Property 3: Password hashing on registration**
*For any* user registration with a password, the stored password value in the database should be a valid bcrypt hash and should not equal the plain text password.
**Validates: Requirements 1.3**
**Property 4: Registration creates session**
*For any* successful user registration, a valid session should be created for that user immediately after registration.
**Validates: Requirements 1.4**
**Property 5: Password length validation**
*For any* password with fewer than 8 characters, registration should be rejected and return a validation error.
**Validates: Requirements 1.5**
### Authentication Properties
**Property 6: Valid credentials create session**
*For any* registered user with known password, submitting correct credentials should authenticate the user and create a valid session.
**Validates: Requirements 2.1**
**Property 7: Invalid credentials rejection**
*For any* login attempt with incorrect password or non-existent email, authentication should fail and return an error.
**Validates: Requirements 2.2**
**Property 8: Session expiration enforcement**
*For any* expired session token, attempting to access protected resources should be denied.
**Validates: Requirements 2.4**
**Property 9: Logout terminates session**
*For any* authenticated user, after logging out, the session token should become invalid and subsequent requests should be denied.
**Validates: Requirements 2.5**
### Session Management Properties
**Property 10: Secure token generation**
*For any* successful login, a session token should be created with sufficient entropy and proper format.
**Validates: Requirements 3.1**
**Property 11: Session persistence**
*For any* valid session token, re-validating the token should maintain the authenticated state with the same user information.
**Validates: Requirements 3.2**
**Property 12: Session duration persistence**
*For any* session created, the session should remain valid for the configured duration even after simulated browser close/reopen.
**Validates: Requirements 3.4**
### List Ownership Properties
**Property 13: List ownership assignment**
*For any* user creating a list, the created list should have its ownerId set to the creating user's ID.
**Validates: Requirements 4.1**
**Property 14: List access filtering**
*For any* user querying for lists, the results should include only lists where the user is the owner or has a collaborator record, and should include all such lists.
**Validates: Requirements 4.2, 4.4**
**Property 15: Unauthorized list access denial**
*For any* user attempting to access a list they don't own and aren't a collaborator on, the access should be denied and return an error.
**Validates: Requirements 4.3**
**Property 16: Account deletion cascades to lists**
*For any* user with owned lists, deleting the user account should result in all owned lists being removed from the database.
**Validates: Requirements 4.5**
### Invitation Properties
**Property 17: Invitation creation with unique ID**
*For any* list owner inviting a user by email, an invitation record should be created with a unique identifier and the specified permission level.
**Validates: Requirements 5.1, 6.1**
**Property 18: Invitation acceptance grants access**
*For any* pending invitation, when the invited user accepts it, a collaborator record should be created granting the user access to the list with the specified permission.
**Validates: Requirements 5.2**
**Property 19: Invitation decline removes record**
*For any* pending invitation, when the invited user declines it, the invitation should be removed from the database.
**Validates: Requirements 5.3**
**Property 20: Collaborator list completeness**
*For any* list with collaborators, querying the collaborators should return all users who have access including their permission levels.
**Validates: Requirements 5.4**
**Property 21: Access revocation enforcement**
*For any* collaborator with access to a list, after the owner revokes access, the user should no longer be able to access the list.
**Validates: Requirements 5.5**
### Permission Properties
**Property 22: Editor permission allows modifications**
*For any* user with editor permission on a list, the user should be able to create, update, and delete items in that list.
**Validates: Requirements 6.2**
**Property 23: Viewer permission prevents modifications**
*For any* user with viewer permission on a list, attempts to create, update, or delete items should be denied and return an error.
**Validates: Requirements 6.3, 6.4**
**Property 24: Permission update enforcement**
*For any* collaborator with editor permission, after the owner changes their permission to viewer, item modification attempts should be denied.
**Validates: Requirements 6.5**
### Profile Management Properties
**Property 25: Profile update persistence**
*For any* user updating profile information, the changes should be saved and associated with the correct user account.
**Validates: Requirements 7.1**
**Property 26: Password change requires current password**
*For any* password change attempt with incorrect current password, the change should be rejected and return an error.
**Validates: Requirements 7.2**
**Property 27: Password hashing on change**
*For any* successful password change, the new password should be stored as a bcrypt hash and not as plain text.
**Validates: Requirements 7.3**
**Property 28: Email uniqueness validation**
*For any* attempt to update email to an address already in use by another user, the update should be rejected and return an error.
**Validates: Requirements 7.4**
**Property 29: Profile data exposure protection**
*For any* user profile query, the returned data should not include the password hash or other sensitive authentication data.
**Validates: Requirements 7.5**
### Invitation Notification Properties
**Property 30: Invitation visibility**
*For any* invitation created for a user's email, querying that user's pending invitations should include the invitation.
**Validates: Requirements 8.1**
**Property 31: Invitation details completeness**
*For any* pending invitation, the invitation data should include the list name and inviter information.
**Validates: Requirements 8.2**
**Property 32: Invitation removal after action**
*For any* invitation that is accepted or declined, the invitation should no longer appear in the user's pending invitations list.
**Validates: Requirements 8.4**
**Property 33: Invitation timestamp recording**
*For any* created invitation, the invitation should have a createdAt timestamp that is set to the time of creation.
**Validates: Requirements 8.5**
### Data Isolation Properties
**Property 34: Item access through list permission**
*For any* user querying items, only items from lists the user has access to should be returned.
**Validates: Requirements 9.2**
### Migration Properties
**Property 35: Migration data preservation**
*For any* list migrated to a user account, all list data including items, metadata, and timestamps should remain unchanged after migration.
**Validates: Requirements 10.3**
## Error Handling
### Authentication Errors
**Invalid Credentials**
- Return clear error messages without revealing whether email exists
- Log failed login attempts for security monitoring
- Implement rate limiting to prevent brute force attacks
**Session Errors**
- Handle expired sessions gracefully with redirect to login
- Clear invalid tokens from client storage
- Provide clear feedback when re-authentication is required
**Registration Errors**
- Validate email format before database query
- Check password requirements client-side and server-side
- Return specific validation errors for each field
### Authorization Errors
**Access Denied**
- Return 403 Forbidden for unauthorized access attempts
- Log unauthorized access attempts
- Provide user-friendly error messages
**Permission Errors**
- Check permissions before executing operations
- Return clear error messages indicating required permission level
- Prevent information leakage about resources user can't access
### Database Errors
**Constraint Violations**
- Handle unique constraint violations (duplicate email)
- Manage foreign key constraints properly
- Use transactions for multi-step operations
**Connection Failures**
- Implement retry logic with exponential backoff
- Provide fallback error messages
- Log database errors for debugging
### Invitation Errors
**Invalid Invitations**
- Validate email format before creating invitation
- Check if user is already a collaborator
- Handle expired invitations gracefully
**Invitation Conflicts**
- Prevent duplicate invitations to same email for same list
- Handle case where invited email doesn't exist yet
- Manage invitation expiration
## Testing Strategy
### Unit Testing
The application will use **Vitest** as the testing framework for unit tests. Unit tests will focus on:
**Authentication Layer**
- Password hashing and verification
- Token generation and validation
- Credential validation logic
- Session creation and management
**Access Control Layer**
- Permission checking functions
- Access control filtering logic
- Collaborator management operations
**Business Logic**
- Invitation creation and acceptance flow
- Profile update operations
- List ownership assignment
- Cascade deletion logic
**Utility Functions**
- Email validation
- Password strength validation
- Token generation
- Data sanitization
Unit tests will use realistic test data and verify specific examples, edge cases, and error conditions.
### Property-Based Testing
The application will use **fast-check** as the property-based testing library. Property-based tests will verify the universal correctness properties defined in this document.
**Configuration Requirements:**
- Each property-based test MUST run a minimum of 100 iterations
- Each test MUST be tagged with a comment referencing the correctness property
- Tag format: `// Feature: user-auth-and-sharing, Property {number}: {property_text}`
- Each correctness property MUST be implemented by a SINGLE property-based test
**Property Test Coverage:**
- User registration (Properties 1-5)
- Authentication (Properties 6-9)
- Session management (Properties 10-12)
- List ownership (Properties 13-16)
- Invitations (Properties 17-21)
- Permissions (Properties 22-24)
- Profile management (Properties 25-29)
- Invitation notifications (Properties 30-33)
- Data isolation (Property 34)
- Migration (Property 35)
**Test Data Generation:**
Property-based tests will use custom generators for:
- Valid email addresses
- Passwords of various lengths
- User IDs (cuid format)
- Permission levels (owner, editor, viewer)
- Invitation statuses
- Session tokens
- Profile data
### Integration Testing
Integration tests will verify:
- End-to-end authentication flows (register → login → access protected resource)
- List sharing workflows (invite → accept → collaborate)
- Permission enforcement across the stack
- Session persistence across requests
- Middleware integration with authentication
### Security Testing
Security tests will verify:
- Password hashing strength
- Session token security
- SQL injection prevention
- XSS prevention in user inputs
- CSRF protection
- Rate limiting effectiveness
## Performance Considerations
### Authentication Performance
- Cache session validation results
- Use efficient bcrypt work factor (10-12 rounds)
- Implement connection pooling for database
- Index user email field for fast lookups
### Access Control Performance
- Index foreign keys (userId, listId in Collaborator table)
- Cache permission checks for frequently accessed lists
- Use database-level filtering for access control
- Implement efficient JOIN queries for list retrieval
### Session Management
- Use stateless JWT tokens to avoid database lookups
- Set appropriate token expiration times
- Implement token refresh mechanism if needed
- Use secure, httpOnly cookies for token storage
## Security Considerations
### Password Security
- Use bcrypt with appropriate work factor (10-12 rounds)
- Enforce minimum password length (8 characters)
- Consider additional password requirements (complexity)
- Never log or expose passwords in plain text
- Implement password reset functionality securely
### Session Security
- Use cryptographically secure random token generation
- Set httpOnly and secure flags on session cookies
- Implement CSRF protection
- Use short session expiration times
- Implement session invalidation on logout
### Access Control Security
- Enforce access control at database query level
- Never trust client-side permission checks
- Validate user identity on every request
- Use parameterized queries to prevent SQL injection
- Implement rate limiting on sensitive operations
### Data Protection
- Encrypt sensitive data at rest
- Use HTTPS for all communications
- Implement proper CORS policies
- Sanitize all user inputs
- Follow principle of least privilege
### Invitation Security
- Implement invitation expiration
- Validate email addresses
- Prevent invitation spam
- Rate limit invitation creation
- Verify inviter has permission to share
## Migration Strategy
### Data Migration
**Phase 1: Schema Updates**
1. Add User table to database
2. Add Collaborator table
3. Add Invitation table
4. Add ownerId field to List table (nullable initially)
**Phase 2: Migration Script**
1. Create a default "system" user for existing lists
2. Associate all existing lists with system user
3. Provide UI for users to claim lists by creating accounts
4. Make ownerId non-nullable after migration
**Phase 3: Deployment**
1. Deploy authentication system
2. Run migration script
3. Enable authentication requirements
4. Monitor for issues
### Backward Compatibility
- Maintain existing API endpoints during transition
- Provide grace period for users to create accounts
- Preserve all existing list and item data
- Ensure PWA functionality continues to work
## Deployment Considerations
### Environment Variables
```
DATABASE_URL=mysql://...
NEXTAUTH_URL=https://yourdomain.com
NEXTAUTH_SECRET=<generated-secret>
JWT_SECRET=<generated-secret>
```
### Database Migrations
1. Run Prisma migrations: `npx prisma migrate dev`
2. Generate Prisma client: `npx prisma generate`
3. Run data migration script if needed
4. Verify schema changes in production
### Monitoring
- Track failed login attempts
- Monitor session creation/expiration
- Log unauthorized access attempts
- Track invitation acceptance rates
- Monitor database query performance
## Future Enhancements
### Authentication Features
- OAuth providers (Google, GitHub, etc.)
- Two-factor authentication
- Password reset via email
- Email verification
- Remember me functionality
- Account recovery options
### Collaboration Features
- Real-time collaboration indicators
- Activity feed for shared lists
- Comments on items
- @mentions in notes
- Notification system for list updates
- Team/organization support
### Permission Enhancements
- Custom permission levels
- Granular item-level permissions
- Temporary access grants
- Permission templates
- Audit log for permission changes

View File

@@ -0,0 +1,140 @@
# Requirements Document
## Introduction
The User Authentication and Sharing feature extends the Ultimate Lists App to support multiple users with private lists and collaborative sharing capabilities. The system SHALL enable users to register accounts, authenticate securely, maintain private lists, and selectively share lists with other users through invitations. This feature transforms the application from a single-user task management tool into a multi-user collaborative platform while maintaining data privacy and security.
## Glossary
- **User**: An individual with a registered account in the Ultimate Lists App
- **Authentication**: The process of verifying a user's identity through credentials
- **Session**: A period of authenticated access to the application
- **Private List**: A list that is only accessible to its owner and invited collaborators
- **List Owner**: The user who created a list and has full control over it
- **Collaborator**: A user who has been granted access to another user's list
- **Invitation**: A request sent by a list owner to grant another user access to a list
- **Permission Level**: The degree of access a user has to a list (owner, editor, viewer)
- **Credential**: User authentication information (email and password)
- **Session Token**: A secure identifier used to maintain authenticated sessions
## Requirements
### Requirement 1: User Registration
**User Story:** As a new user, I want to register for an account with my email and password, so that I can have my own private lists.
#### Acceptance Criteria
1. WHEN a user submits a registration form with a valid email and password, THE Ultimate Lists App SHALL create a new user account with a unique identifier
2. WHEN a user attempts to register with an email that already exists, THE Ultimate Lists App SHALL reject the registration and display an error message
3. WHEN a user registers, THE Ultimate Lists App SHALL hash the password before storing it in the database
4. WHEN a user completes registration, THE Ultimate Lists App SHALL create an authenticated session for that user
5. WHEN a user provides a password during registration, THE Ultimate Lists App SHALL validate that the password meets minimum security requirements (at least 8 characters)
### Requirement 2: User Authentication
**User Story:** As a registered user, I want to log in with my email and password, so that I can access my private lists.
#### Acceptance Criteria
1. WHEN a user submits valid credentials, THE Ultimate Lists App SHALL authenticate the user and create a session
2. WHEN a user submits invalid credentials, THE Ultimate Lists App SHALL reject the login attempt and display an error message
3. WHEN a user logs in successfully, THE Ultimate Lists App SHALL redirect the user to their lists dashboard
4. WHEN a user session expires, THE Ultimate Lists App SHALL require re-authentication before allowing access to protected resources
5. WHEN a user logs out, THE Ultimate Lists App SHALL terminate the session and clear authentication tokens
### Requirement 3: Session Management
**User Story:** As a logged-in user, I want my session to persist across page refreshes, so that I don't have to log in repeatedly.
#### Acceptance Criteria
1. WHEN a user logs in, THE Ultimate Lists App SHALL create a secure session token
2. WHEN a user refreshes the page, THE Ultimate Lists App SHALL validate the session token and maintain the authenticated state
3. WHEN a session token is invalid or expired, THE Ultimate Lists App SHALL redirect the user to the login page
4. WHEN a user closes the browser, THE Ultimate Lists App SHALL preserve the session for a configurable duration
5. WHEN a user accesses a protected route without authentication, THE Ultimate Lists App SHALL redirect to the login page
### Requirement 4: Private Lists
**User Story:** As a user, I want all my lists to be private by default, so that only I can see and modify them.
#### Acceptance Criteria
1. WHEN a user creates a list, THE Ultimate Lists App SHALL associate the list with the user's account as the owner
2. WHEN a user views their lists, THE Ultimate Lists App SHALL display only lists they own or have been granted access to
3. WHEN a user attempts to access another user's private list without permission, THE Ultimate Lists App SHALL deny access and return an error
4. WHEN a user queries for lists, THE Ultimate Lists App SHALL filter results to include only lists the user has permission to view
5. WHEN a user deletes their account, THE Ultimate Lists App SHALL delete all lists owned by that user
### Requirement 5: List Sharing and Invitations
**User Story:** As a list owner, I want to invite other users to collaborate on my lists, so that we can work together on shared tasks.
#### Acceptance Criteria
1. WHEN a list owner invites a user by email, THE Ultimate Lists App SHALL create an invitation record with a unique identifier
2. WHEN an invited user accepts an invitation, THE Ultimate Lists App SHALL grant the user access to the shared list
3. WHEN an invited user declines an invitation, THE Ultimate Lists App SHALL remove the invitation record
4. WHEN a list owner views a list, THE Ultimate Lists App SHALL display all users who have access to that list
5. WHEN a list owner revokes a user's access, THE Ultimate Lists App SHALL remove the user's permission and prevent further access to the list
### Requirement 6: Collaboration Permissions
**User Story:** As a list owner, I want to control what collaborators can do with my lists, so that I can maintain appropriate access levels.
#### Acceptance Criteria
1. WHEN a list owner invites a collaborator, THE Ultimate Lists App SHALL allow the owner to specify a permission level (editor or viewer)
2. WHEN a user with editor permission accesses a shared list, THE Ultimate Lists App SHALL allow the user to create, edit, and delete items
3. WHEN a user with viewer permission accesses a shared list, THE Ultimate Lists App SHALL allow the user to view items but prevent modifications
4. WHEN a user attempts an action beyond their permission level, THE Ultimate Lists App SHALL deny the action and display an error message
5. WHEN a list owner changes a collaborator's permission level, THE Ultimate Lists App SHALL update the permission and enforce the new access level immediately
### Requirement 7: User Profile Management
**User Story:** As a user, I want to manage my profile information, so that I can update my details and change my password.
#### Acceptance Criteria
1. WHEN a user updates their profile information, THE Ultimate Lists App SHALL save the changes and associate them with the user's account
2. WHEN a user changes their password, THE Ultimate Lists App SHALL validate the current password before allowing the change
3. WHEN a user changes their password, THE Ultimate Lists App SHALL hash the new password before storing it
4. WHEN a user updates their email address, THE Ultimate Lists App SHALL verify that the new email is not already in use
5. WHEN a user views their profile, THE Ultimate Lists App SHALL display their current information without exposing sensitive data like password hashes
### Requirement 8: Invitation Notifications
**User Story:** As an invited user, I want to be notified when someone shares a list with me, so that I can accept or decline the invitation.
#### Acceptance Criteria
1. WHEN a user receives an invitation, THE Ultimate Lists App SHALL display the invitation in the user's notifications or invitations list
2. WHEN a user views pending invitations, THE Ultimate Lists App SHALL display the list name and the inviter's information
3. WHEN a user has pending invitations, THE Ultimate Lists App SHALL display a notification indicator
4. WHEN a user accepts or declines an invitation, THE Ultimate Lists App SHALL remove it from the pending invitations list
5. WHEN an invitation is created, THE Ultimate Lists App SHALL record the invitation timestamp
### Requirement 9: Data Isolation and Security
**User Story:** As a user, I want my data to be secure and isolated from other users, so that my privacy is protected.
#### Acceptance Criteria
1. WHEN the system queries for lists, THE Ultimate Lists App SHALL enforce user-based access control at the database query level
2. WHEN the system queries for items, THE Ultimate Lists App SHALL ensure items are only returned if the user has access to the parent list
3. WHEN a user attempts to access a resource, THE Ultimate Lists App SHALL verify the user's authentication before processing the request
4. WHEN the system stores passwords, THE Ultimate Lists App SHALL use a secure hashing algorithm with salt
5. WHEN the system creates session tokens, THE Ultimate Lists App SHALL generate cryptographically secure random tokens
### Requirement 10: Migration of Existing Data
**User Story:** As an existing user of the app, I want my current lists to be preserved when the authentication system is added, so that I don't lose my data.
#### Acceptance Criteria
1. WHEN the authentication system is deployed, THE Ultimate Lists App SHALL provide a migration path for existing anonymous lists
2. WHEN an existing user registers for the first time, THE Ultimate Lists App SHALL associate any existing lists with the new user account
3. WHEN lists are migrated to a user account, THE Ultimate Lists App SHALL preserve all list data including items, metadata, and timestamps
4. WHEN the migration is complete, THE Ultimate Lists App SHALL ensure all lists have an associated owner
5. WHEN a user accesses the app after migration, THE Ultimate Lists App SHALL display all their migrated lists in their account

View File

@@ -0,0 +1,283 @@
# Implementation Plan
- [x] 1. Set up authentication infrastructure
- Install and configure NextAuth.js v5, bcryptjs, and zod
- Create auth configuration file with credentials provider
- Set up environment variables for auth secrets
- _Requirements: 1.1, 2.1_
- [ ] 2. Update database schema for multi-user support
- Add User model with email, passwordHash, and name fields
- Add Collaborator model for list sharing
- Add Invitation model for sharing invitations
- Add ownerId field to List model
- Add necessary indexes for performance
- _Requirements: 1.1, 4.1, 5.1_
- [ ]* 2.1 Write property test for user registration
- **Property 1: Registration creates unique user**
- **Validates: Requirements 1.1**
- [ ]* 2.2 Write property test for duplicate email rejection
- **Property 2: Duplicate email rejection**
- **Validates: Requirements 1.2**
- [ ]* 2.3 Write property test for password hashing
- **Property 3: Password hashing on registration**
- **Validates: Requirements 1.3**
- [ ] 3. Implement user registration functionality
- Create registration server action with email/password validation
- Implement password hashing with bcrypt
- Add email uniqueness check
- Create session after successful registration
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5_
- [ ]* 3.1 Write property test for registration session creation
- **Property 4: Registration creates session**
- **Validates: Requirements 1.4**
- [ ]* 3.2 Write property test for password length validation
- **Property 5: Password length validation**
- **Validates: Requirements 1.5**
- [ ] 4. Implement authentication functionality
- Create login server action with credential validation
- Implement password verification with bcrypt
- Create session on successful login
- Handle invalid credentials with appropriate errors
- _Requirements: 2.1, 2.2_
- [ ]* 4.1 Write property test for valid credentials
- **Property 6: Valid credentials create session**
- **Validates: Requirements 2.1**
- [ ]* 4.2 Write property test for invalid credentials
- **Property 7: Invalid credentials rejection**
- **Validates: Requirements 2.2**
- [ ] 5. Implement session management
- Configure JWT session strategy in NextAuth
- Implement session validation middleware
- Create logout functionality
- Handle session expiration
- _Requirements: 2.4, 2.5, 3.1, 3.2, 3.4_
- [ ]* 5.1 Write property test for session expiration
- **Property 8: Session expiration enforcement**
- **Validates: Requirements 2.4**
- [ ]* 5.2 Write property test for logout
- **Property 9: Logout terminates session**
- **Validates: Requirements 2.5**
- [ ]* 5.3 Write property test for secure token generation
- **Property 10: Secure token generation**
- **Validates: Requirements 3.1**
- [ ]* 5.4 Write property test for session persistence
- **Property 11: Session persistence**
- **Validates: Requirements 3.2**
- [ ]* 5.5 Write property test for session duration
- **Property 12: Session duration persistence**
- **Validates: Requirements 3.4**
- [ ] 6. Create authentication UI components
- Build LoginForm component with email/password inputs
- Build RegisterForm component with validation
- Create authentication error display page
- Add loading states and error handling
- _Requirements: 1.1, 2.1_
- [ ] 7. Implement route protection middleware
- Create Next.js middleware for authentication checks
- Protect main routes (/, /list/*, /profile/*)
- Redirect unauthenticated users to login
- _Requirements: 3.3, 3.5_
- [ ] 8. Update list operations for ownership
- Modify createList to assign ownerId
- Update getLists to filter by user access
- Add ownership checks to updateList and deleteList
- Implement cascade deletion for user account deletion
- _Requirements: 4.1, 4.2, 4.3, 4.5_
- [ ]* 8.1 Write property test for list ownership assignment
- **Property 13: List ownership assignment**
- **Validates: Requirements 4.1**
- [ ]* 8.2 Write property test for list access filtering
- **Property 14: List access filtering**
- **Validates: Requirements 4.2, 4.4**
- [ ]* 8.3 Write property test for unauthorized access denial
- **Property 15: Unauthorized list access denial**
- **Validates: Requirements 4.3**
- [ ]* 8.4 Write property test for account deletion cascade
- **Property 16: Account deletion cascades to lists**
- **Validates: Requirements 4.5**
- [ ] 9. Implement permission utilities
- Create canAccessList function
- Create canEditList function
- Create canDeleteList function
- Create getPermission function
- _Requirements: 4.3, 6.2, 6.3_
- [ ] 10. Update item operations for access control
- Add access checks to createItem
- Add access checks to updateItem, deleteItem, toggleItem
- Enforce editor vs viewer permissions
- Filter items by list access in queries
- _Requirements: 6.2, 6.3, 9.2_
- [ ]* 10.1 Write property test for item access through list permission
- **Property 34: Item access through list permission**
- **Validates: Requirements 9.2**
- [ ] 11. Implement invitation system
- Create inviteUserToList server action
- Create getInvitations server action
- Create acceptInvitation server action
- Create declineInvitation server action
- Add invitation expiration logic
- _Requirements: 5.1, 5.2, 5.3, 8.1, 8.5_
- [ ]* 11.1 Write property test for invitation creation
- **Property 17: Invitation creation with unique ID**
- **Validates: Requirements 5.1, 6.1**
- [ ]* 11.2 Write property test for invitation acceptance
- **Property 18: Invitation acceptance grants access**
- **Validates: Requirements 5.2**
- [ ]* 11.3 Write property test for invitation decline
- **Property 19: Invitation decline removes record**
- **Validates: Requirements 5.3**
- [ ]* 11.4 Write property test for invitation visibility
- **Property 30: Invitation visibility**
- **Validates: Requirements 8.1**
- [ ]* 11.5 Write property test for invitation details
- **Property 31: Invitation details completeness**
- **Validates: Requirements 8.2**
- [ ]* 11.6 Write property test for invitation removal
- **Property 32: Invitation removal after action**
- **Validates: Requirements 8.4**
- [ ]* 11.7 Write property test for invitation timestamp
- **Property 33: Invitation timestamp recording**
- **Validates: Requirements 8.5**
- [ ] 12. Implement collaborator management
- Create getCollaborators server action
- Create updateCollaboratorPermission server action
- Create removeCollaborator server action
- Add permission level enforcement
- _Requirements: 5.4, 5.5, 6.1, 6.5_
- [ ]* 12.1 Write property test for collaborator list
- **Property 20: Collaborator list completeness**
- **Validates: Requirements 5.4**
- [ ]* 12.2 Write property test for access revocation
- **Property 21: Access revocation enforcement**
- **Validates: Requirements 5.5**
- [ ]* 12.3 Write property test for editor permissions
- **Property 22: Editor permission allows modifications**
- **Validates: Requirements 6.2**
- [ ]* 12.4 Write property test for viewer permissions
- **Property 23: Viewer permission prevents modifications**
- **Validates: Requirements 6.3, 6.4**
- [ ]* 12.5 Write property test for permission updates
- **Property 24: Permission update enforcement**
- **Validates: Requirements 6.5**
- [ ] 13. Create sharing UI components
- Build InvitationCard component
- Build CollaboratorList component
- Build ShareListModal component
- Build PermissionBadge component
- Add invitations page
- _Requirements: 5.1, 5.4, 8.1, 8.2_
- [ ] 14. Implement profile management
- Create profile page and ProfileForm component
- Implement updateProfile server action
- Create PasswordChangeForm component
- Implement updatePassword server action with current password verification
- Add email update with uniqueness check
- _Requirements: 7.1, 7.2, 7.3, 7.4, 7.5_
- [ ]* 14.1 Write property test for profile updates
- **Property 25: Profile update persistence**
- **Validates: Requirements 7.1**
- [ ]* 14.2 Write property test for password change validation
- **Property 26: Password change requires current password**
- **Validates: Requirements 7.2**
- [ ]* 14.3 Write property test for password hashing on change
- **Property 27: Password hashing on change**
- **Validates: Requirements 7.3**
- [ ]* 14.4 Write property test for email uniqueness
- **Property 28: Email uniqueness validation**
- **Validates: Requirements 7.4**
- [ ]* 14.5 Write property test for profile data exposure
- **Property 29: Profile data exposure protection**
- **Validates: Requirements 7.5**
- [ ] 15. Update existing components for multi-user
- Modify ListCard to show sharing indicator
- Update ListDetailView with share button and permission display
- Modify ItemForm to disable editing for viewers
- Update navigation to include profile and invitations links
- _Requirements: 6.3_
- [ ] 16. Implement data migration for existing lists
- Create migration script for existing anonymous lists
- Add UI for users to claim existing lists on first registration
- Ensure all lists have an owner after migration
- Preserve all existing list and item data
- _Requirements: 10.2, 10.3, 10.4, 10.5_
- [ ]* 16.1 Write property test for migration data preservation
- **Property 35: Migration data preservation**
- **Validates: Requirements 10.3**
- [ ] 17. Add security enhancements
- Implement rate limiting on login attempts
- Add CSRF protection
- Implement secure session cookie configuration
- Add input sanitization for all user inputs
- _Requirements: 9.3, 9.4, 9.5_
- [ ] 18. Checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
- [ ] 19. Update PWA service worker for authentication
- Handle authentication errors in offline mode
- Cache authentication-related pages appropriately
- Update manifest if needed
- Test offline behavior with authentication
- _Requirements: 4.4_
- [ ] 20. Final integration and testing
- Test complete authentication flow end-to-end
- Test list sharing workflow end-to-end
- Verify permission enforcement across all operations
- Test migration process with sample data
- Verify PWA functionality still works
- _Requirements: All_
- [ ] 21. Final Checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.

110
AUTH_SETUP.md Normal file
View File

@@ -0,0 +1,110 @@
# Authentication Setup
This document describes the authentication infrastructure setup for the Ultimate Lists App.
## Installed Dependencies
- **next-auth@5.0.0-beta** - NextAuth.js v5 (Auth.js) for authentication
- **bcryptjs** - Password hashing library
- **zod** - Schema validation for forms and API inputs
- **@auth/prisma-adapter** - Prisma adapter for NextAuth
- **@types/bcryptjs** - TypeScript types for bcryptjs
## Configuration Files
### `auth.ts`
Main authentication configuration file that exports:
- `handlers` - HTTP handlers for the auth API routes
- `signIn` - Function to sign in users
- `signOut` - Function to sign out users
- `auth` - Function to get the current session
Features:
- Credentials provider for email/password authentication
- JWT session strategy
- Password verification with bcrypt
- Custom callbacks for JWT and session
- Custom auth pages configuration
### `auth.config.ts`
Edge-compatible auth configuration for middleware:
- Route authorization logic
- Custom auth pages
- Provider configuration placeholder
### `types/next-auth.d.ts`
TypeScript type extensions for NextAuth:
- Adds `id` field to Session user
- Adds `id` field to JWT token
- Defines User interface
### `app/api/auth/[...nextauth]/route.ts`
API route handler that exports GET and POST handlers from NextAuth.
## Environment Variables
The following environment variables have been added to `.env`:
```env
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here-please-change-in-production
AUTH_SECRET=your-secret-key-here-please-change-in-production
```
**Important:** Generate secure secrets for production using:
```bash
openssl rand -base64 32
```
## Next Steps
1. Update the Prisma schema to add User, Collaborator, and Invitation models (Task 2)
2. Implement user registration functionality (Task 3)
3. Implement authentication functionality (Task 4)
4. Create authentication UI components (Task 6)
5. Implement route protection middleware (Task 7)
## Usage
### Getting the current session
```typescript
import { auth } from "@/auth"
export default async function Page() {
const session = await auth()
if (!session?.user) {
// User is not authenticated
return <div>Please log in</div>
}
// User is authenticated
return <div>Welcome {session.user.email}</div>
}
```
### Sign in
```typescript
import { signIn } from "@/auth"
await signIn("credentials", {
email: "user@example.com",
password: "password123",
redirectTo: "/",
})
```
### Sign out
```typescript
import { signOut } from "@/auth"
await signOut({ redirectTo: "/auth/login" })
```
## Security Notes
- Passwords are hashed using bcrypt before storage
- JWT tokens are used for stateless sessions
- Session tokens are stored in httpOnly cookies
- All credentials are validated using Zod schemas
- Failed login attempts return null without revealing whether email exists

View File

@@ -0,0 +1,3 @@
import { handlers } from "@/auth"
export const { GET, POST } = handlers

28
auth.config.ts Normal file
View File

@@ -0,0 +1,28 @@
import type { NextAuthConfig } from "next-auth"
export const authConfig = {
pages: {
signIn: "/auth/login",
signOut: "/auth/logout",
error: "/auth/error",
},
callbacks: {
authorized({ auth, request: { nextUrl } }) {
const isLoggedIn = !!auth?.user
const isOnAuthPage = nextUrl.pathname.startsWith("/auth")
// Allow access to auth pages when not logged in
if (isOnAuthPage) {
return true
}
// Redirect to login if not authenticated
if (!isLoggedIn) {
return false
}
return true
},
},
providers: [], // Providers will be added in auth.ts
} satisfies NextAuthConfig

82
auth.ts Normal file
View File

@@ -0,0 +1,82 @@
import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
import { PrismaAdapter } from "@auth/prisma-adapter"
import { prisma } from "@/lib/db"
import bcrypt from "bcryptjs"
import { z } from "zod"
// Validation schemas
const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(1),
})
export const { handlers, signIn, signOut, auth } = NextAuth({
adapter: PrismaAdapter(prisma),
session: {
strategy: "jwt",
},
providers: [
Credentials({
name: "credentials",
credentials: {
email: { label: "Email", type: "email" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
try {
// Validate credentials format
const { email, password } = loginSchema.parse(credentials)
// Query user from database
const user = await prisma.user.findUnique({
where: { email },
})
// Check if user exists
if (!user || !user.passwordHash) {
return null
}
// Verify password with bcrypt
const isPasswordValid = await bcrypt.compare(password, user.passwordHash)
if (!isPasswordValid) {
return null
}
// Return user object (without password hash)
return {
id: user.id,
email: user.email,
name: user.name,
}
} catch (error) {
console.error("Authorization error:", error)
return null
}
},
}),
],
callbacks: {
async jwt({ token, user }) {
// Add user ID to token on sign in
if (user) {
token.id = user.id
}
return token
},
async session({ session, token }) {
// Add user ID to session from token
if (session.user) {
session.user.id = token.id as string
}
return session
},
},
pages: {
signIn: "/auth/login",
signOut: "/auth/logout",
error: "/auth/error",
},
})

175
package-lock.json generated
View File

@@ -8,14 +8,19 @@
"name": "ultimate-lists-app", "name": "ultimate-lists-app",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@auth/prisma-adapter": "^2.11.1",
"@prisma/client": "^5.7.1", "@prisma/client": "^5.7.1",
"bcryptjs": "^3.0.3",
"lucide-react": "^0.294.0", "lucide-react": "^0.294.0",
"mysql2": "^3.15.3", "mysql2": "^3.15.3",
"next": "14.0.4", "next": "14.0.4",
"next-auth": "^5.0.0-beta.30",
"react": "^18", "react": "^18",
"react-dom": "^18" "react-dom": "^18",
"zod": "^4.1.13"
}, },
"devDependencies": { "devDependencies": {
"@types/bcryptjs": "^2.4.6",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",
@@ -41,6 +46,76 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/@auth/core": {
"version": "0.41.0",
"resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.0.tgz",
"integrity": "sha512-Wd7mHPQ/8zy6Qj7f4T46vg3aoor8fskJm6g2Zyj064oQ3+p0xNZXAV60ww0hY+MbTesfu29kK14Zk5d5JTazXQ==",
"license": "ISC",
"dependencies": {
"@panva/hkdf": "^1.2.1",
"jose": "^6.0.6",
"oauth4webapi": "^3.3.0",
"preact": "10.24.3",
"preact-render-to-string": "6.5.11"
},
"peerDependencies": {
"@simplewebauthn/browser": "^9.0.1",
"@simplewebauthn/server": "^9.0.2",
"nodemailer": "^6.8.0"
},
"peerDependenciesMeta": {
"@simplewebauthn/browser": {
"optional": true
},
"@simplewebauthn/server": {
"optional": true
},
"nodemailer": {
"optional": true
}
}
},
"node_modules/@auth/prisma-adapter": {
"version": "2.11.1",
"resolved": "https://registry.npmjs.org/@auth/prisma-adapter/-/prisma-adapter-2.11.1.tgz",
"integrity": "sha512-Ke7DXP0Fy0Mlmjz/ZJLXwQash2UkA4621xCM0rMtEczr1kppLc/njCbUkHkIQ/PnmILjqSPEKeTjDPsYruvkug==",
"license": "ISC",
"dependencies": {
"@auth/core": "0.41.1"
},
"peerDependencies": {
"@prisma/client": ">=2.26.0 || >=3 || >=4 || >=5 || >=6"
}
},
"node_modules/@auth/prisma-adapter/node_modules/@auth/core": {
"version": "0.41.1",
"resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.1.tgz",
"integrity": "sha512-t9cJ2zNYAdWMacGRMT6+r4xr1uybIdmYa49calBPeTqwgAFPV/88ac9TEvCR85pvATiSPt8VaNf+Gt24JIT/uw==",
"license": "ISC",
"dependencies": {
"@panva/hkdf": "^1.2.1",
"jose": "^6.0.6",
"oauth4webapi": "^3.3.0",
"preact": "10.24.3",
"preact-render-to-string": "6.5.11"
},
"peerDependencies": {
"@simplewebauthn/browser": "^9.0.1",
"@simplewebauthn/server": "^9.0.2",
"nodemailer": "^7.0.7"
},
"peerDependenciesMeta": {
"@simplewebauthn/browser": {
"optional": true
},
"@simplewebauthn/server": {
"optional": true
},
"nodemailer": {
"optional": true
}
}
},
"node_modules/@emnapi/core": { "node_modules/@emnapi/core": {
"version": "1.7.1", "version": "1.7.1",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz",
@@ -436,6 +511,15 @@
"node": ">=12.4.0" "node": ">=12.4.0"
} }
}, },
"node_modules/@panva/hkdf": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
"integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/@prisma/client": { "node_modules/@prisma/client": {
"version": "5.22.0", "version": "5.22.0",
"resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz",
@@ -538,6 +622,13 @@
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
}, },
"node_modules/@types/bcryptjs": {
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz",
"integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/json5": { "node_modules/@types/json5": {
"version": "0.0.29", "version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -1391,6 +1482,15 @@
"baseline-browser-mapping": "dist/cli.js" "baseline-browser-mapping": "dist/cli.js"
} }
}, },
"node_modules/bcryptjs": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.3.tgz",
"integrity": "sha512-GlF5wPWnSa/X5LKM1o0wz0suXIINz1iHRLvTS+sLyi7XPbe5ycmYI3DlZqVGZZtDgl4DmasFg7gOB3JYbphV5g==",
"license": "BSD-3-Clause",
"bin": {
"bcrypt": "bin/bcrypt"
}
},
"node_modules/binary-extensions": { "node_modules/binary-extensions": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -3626,6 +3726,15 @@
"jiti": "bin/jiti.js" "jiti": "bin/jiti.js"
} }
}, },
"node_modules/jose": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.2.tgz",
"integrity": "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/js-tokens": { "node_modules/js-tokens": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -4029,6 +4138,33 @@
} }
} }
}, },
"node_modules/next-auth": {
"version": "5.0.0-beta.30",
"resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.30.tgz",
"integrity": "sha512-+c51gquM3F6nMVmoAusRJ7RIoY0K4Ts9HCCwyy/BRoe4mp3msZpOzYMyb5LAYc1wSo74PMQkGDcaghIO7W6Xjg==",
"license": "ISC",
"dependencies": {
"@auth/core": "0.41.0"
},
"peerDependencies": {
"@simplewebauthn/browser": "^9.0.1",
"@simplewebauthn/server": "^9.0.2",
"next": "^14.0.0-0 || ^15.0.0 || ^16.0.0",
"nodemailer": "^7.0.7",
"react": "^18.2.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@simplewebauthn/browser": {
"optional": true
},
"@simplewebauthn/server": {
"optional": true
},
"nodemailer": {
"optional": true
}
}
},
"node_modules/next/node_modules/postcss": { "node_modules/next/node_modules/postcss": {
"version": "8.4.31", "version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
@@ -4084,6 +4220,15 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/oauth4webapi": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.3.tgz",
"integrity": "sha512-pQ5BsX3QRTgnt5HxgHwgunIRaDXBdkT23tf8dfzmtTIL2LTpdmxgbpbBm0VgFWAIDlezQvQCTgnVIUmHupXHxw==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/object-assign": { "node_modules/object-assign": {
"version": "4.1.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -4567,6 +4712,25 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/preact": {
"version": "10.24.3",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
"license": "MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/preact-render-to-string": {
"version": "6.5.11",
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz",
"integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==",
"license": "MIT",
"peerDependencies": {
"preact": ">=10"
}
},
"node_modules/prelude-ls": { "node_modules/prelude-ls": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -5888,6 +6052,15 @@
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
},
"node_modules/zod": {
"version": "4.1.13",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz",
"integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
} }
} }
} }

View File

@@ -13,14 +13,19 @@
"icons:info": "node scripts/svg-to-png.js" "icons:info": "node scripts/svg-to-png.js"
}, },
"dependencies": { "dependencies": {
"@auth/prisma-adapter": "^2.11.1",
"@prisma/client": "^5.7.1", "@prisma/client": "^5.7.1",
"bcryptjs": "^3.0.3",
"lucide-react": "^0.294.0", "lucide-react": "^0.294.0",
"mysql2": "^3.15.3", "mysql2": "^3.15.3",
"next": "14.0.4", "next": "14.0.4",
"next-auth": "^5.0.0-beta.30",
"react": "^18", "react": "^18",
"react-dom": "^18" "react-dom": "^18",
"zod": "^4.1.13"
}, },
"devDependencies": { "devDependencies": {
"@types/bcryptjs": "^2.4.6",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "^18", "@types/react": "^18",
"@types/react-dom": "^18", "@types/react-dom": "^18",

21
types/next-auth.d.ts vendored Normal file
View File

@@ -0,0 +1,21 @@
import { DefaultSession } from "next-auth"
declare module "next-auth" {
interface Session {
user: {
id: string
} & DefaultSession["user"]
}
interface User {
id: string
email: string
name: string | null
}
}
declare module "next-auth/jwt" {
interface JWT {
id: string
}
}