Skip to content
216 changes: 216 additions & 0 deletions docs/multiuser/phase4_summary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Phase 4 Implementation Summary

## Overview

Phase 4 of the InvokeAI multiuser support adds multi-tenancy to the core services, ensuring that users can only access their own data and data that has been explicitly shared with them.

## Implementation Date

January 8, 2026

## Changes Made

### 1. Boards Service

#### Updated Files
- `invokeai/app/services/board_records/board_records_base.py`
- `invokeai/app/services/board_records/board_records_sqlite.py`
- `invokeai/app/services/boards/boards_base.py`
- `invokeai/app/services/boards/boards_default.py`
- `invokeai/app/api/routers/boards.py`

#### Key Changes
- Added `user_id` parameter to `save()`, `get_many()`, and `get_all()` methods
- Updated SQL queries to filter boards by user ownership, shared access, or public status
- Queries now use LEFT JOIN with `shared_boards` table to include boards shared with the user
- Added `CurrentUser` dependency to all board API endpoints
- Board creation now associates boards with the creating user
- Board listing returns only boards the user owns, boards shared with them, or public boards

#### SQL Query Pattern
```sql
SELECT DISTINCT boards.*
FROM boards
LEFT JOIN shared_boards ON boards.board_id = shared_boards.board_id
WHERE (boards.user_id = ? OR shared_boards.user_id = ? OR boards.is_public = 1)
AND boards.archived = 0
ORDER BY created_at DESC
```

### 2. Session Queue Service

#### Updated Files
- `invokeai/app/services/session_queue/session_queue_common.py`
- `invokeai/app/services/session_queue/session_queue_base.py`
- `invokeai/app/services/session_queue/session_queue_sqlite.py`
- `invokeai/app/api/routers/session_queue.py`

#### Key Changes
- Added `user_id` field to `SessionQueueItem` model
- Updated `ValueToInsertTuple` type alias to include `user_id`
- Modified `prepare_values_to_insert()` to accept and include `user_id`
- Updated `enqueue_batch()` method signature to accept `user_id` parameter
- Modified SQL INSERT statements to include `user_id` column
- Updated `retry_items_by_id()` to preserve `user_id` when retrying failed items
- Added `CurrentUser` dependency to `enqueue_batch` API endpoint

### 3. Invocation Context

#### Updated Files
- `invokeai/app/services/shared/invocation_context.py`

#### Key Changes
- Updated `BoardsInterface.create()` to extract `user_id` from queue item and pass to boards service
- Updated `BoardsInterface.get_all()` to extract `user_id` from queue item and pass to boards service
- Invocations now automatically respect user ownership when creating or listing boards

### 4. Images, Workflows, and Style Presets Routers

#### Updated Files
- `invokeai/app/api/routers/images.py`
- `invokeai/app/api/routers/workflows.py`
- `invokeai/app/api/routers/style_presets.py`

#### Key Changes
- Added `CurrentUser` import to all three routers
- Updated `upload_image` endpoint to require authentication
- Prepared routers for full multi-user filtering (to be completed in follow-up work)

## Data Flow

### Board Creation via API
1. User makes authenticated request to `POST /v1/boards/`
2. `CurrentUser` dependency extracts user_id from JWT token
3. Boards service creates board with `user_id`
4. Board is stored in database with user ownership

### Board Creation via Invocation
1. User enqueues a batch with authenticated request
2. Session queue item is created with `user_id` from token
3. Invocation executes and calls `context.boards.create()`
4. Invocation context extracts `user_id` from queue item
5. Board is created with correct user ownership

### Board Listing
1. User makes authenticated request to `GET /v1/boards/`
2. `CurrentUser` dependency provides user_id
3. SQL query returns:
- Boards owned by the user (`boards.user_id = user_id`)
- Boards shared with the user (`shared_boards.user_id = user_id`)
- Public boards (`boards.is_public = 1`)
4. Results are returned to user

## Security Considerations

### Access Control
- All board operations now require authentication
- Users can only see boards they own, boards shared with them, or public boards
- Board creation automatically associates with the creating user
- Session queue items track which user created them

### Data Isolation
- Database queries use parameterized statements to prevent SQL injection
- User IDs are extracted from verified JWT tokens
- No board data leaks between users unless explicitly shared

### Backward Compatibility
- Default `user_id` is "system" for backward compatibility
- Existing data from before multiuser support is owned by "system" user
- Migration 25 added user_id columns with default value of "system"

## Testing

### Test Coverage
- Created `tests/app/routers/test_boards_multiuser.py`
- Tests verify authentication requirements for board operations
- Tests verify board creation and listing with authentication
- Tests include isolation verification (placeholder for full implementation)

### Manual Testing
To test manually:

1. Setup admin user:
```bash
curl -X POST http://localhost:9090/api/v1/auth/setup \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"display_name": "Admin",
"password": "TestPass123"
}'
```

2. Get authentication token:
```bash
curl -X POST http://localhost:9090/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "TestPass123"
}'
```

3. Create a board:
```bash
curl -X POST "http://localhost:9090/api/v1/boards/?board_name=My+Board" \
-H "Authorization: Bearer <token>"
```

4. List boards:
```bash
curl -X GET "http://localhost:9090/api/v1/boards/?all=true" \
-H "Authorization: Bearer <token>"
```

## Known Limitations

### Not Yet Implemented
1. **User-based filtering for images**: While images are created through sessions (which now have user_id), direct image queries don't yet filter by user
2. **Workflow filtering**: Workflows need user_id and is_public filtering
3. **Style preset filtering**: Style presets need user_id and is_public filtering
4. **Admin bypass**: Admins should be able to see all data, not just their own

### Future Enhancements
1. **Board sharing management**: API endpoints to share/unshare boards
2. **Permission levels**: Different access levels (read-only vs. edit)
3. **Bulk operations**: Update or delete multiple boards at once
4. **Audit logging**: Track who accessed or modified what

## Migration Impact

### Database
- Migration 25 (completed in Phase 1) added necessary columns
- No additional migrations needed for Phase 4
- Existing data is accessible via "system" user

### API Compatibility
- **Breaking Change**: All board operations now require authentication
- **Breaking Change**: Session queue enqueue now requires authentication
- Frontend will need to include auth tokens in all requests
- Existing scripts/tools must be updated to authenticate

### Performance
- LEFT JOIN adds minor overhead to board queries
- Indexes on user_id columns provide good query performance
- No significant performance degradation expected

## Next Steps

### Immediate
1. Complete image filtering implementation
2. Complete workflow filtering implementation
3. Complete style preset filtering implementation
4. Add admin bypass for all operations
5. Expand test coverage

### Future Phases
- Phase 5: Frontend authentication UI
- Phase 6: User management UI
- Phase 7: Board sharing UI
- Phase 8: Permission management

## References

- Implementation Plan: `docs/multiuser/implementation_plan.md`
- Database Migration: `invokeai/app/services/shared/sqlite_migrator/migrations/migration_25.py`
- Phase 3 Verification: `docs/multiuser/phase3_verification.md`
Loading