managarten/memoro/apps/mobile/docs/SPACES.md
Till-JS e7f5f942f3 chore: initial commit - consolidate 4 projects into monorepo
Projects included:
- maerchenzauber (NestJS backend + Expo mobile + SvelteKit web + Astro landing)
- manacore (Expo mobile + SvelteKit web + Astro landing)
- manadeck (NestJS backend + Expo mobile + SvelteKit web)
- memoro (Expo mobile + SvelteKit web + Astro landing)

This commit preserves the current state before monorepo restructuring.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 23:38:24 +01:00

278 lines
No EOL
7.9 KiB
Markdown

# Spaces Feature Documentation
## Overview
Spaces in Memoro allow users to organize their memories and memos into logical containers. This feature provides a way to categorize content, manage access, and facilitate organization of user data.
## Architecture
The Spaces feature uses a centralized approach for data management with fast local access:
1. **Express Backend API**: Serves as the source of truth for space management
2. **Memoro App (Client)**: Interfaces with the Express Backend API
3. **Supabase Database**: Used by both the Express Backend and the app for data storage and retrieval
This architecture allows the app to perform operations through the Express Backend API, which then directly updates the Supabase database. This ensures a single source of truth while still enabling fast data access.
## Implementation Details
### Database Schema
In Memoro's local Supabase database:
```sql
-- Spaces table
CREATE TABLE public.spaces (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
description TEXT DEFAULT '',
color TEXT DEFAULT '#4CAF50',
user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
is_default BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Junction table linking memos to spaces
CREATE TABLE public.memo_spaces (
memo_id UUID NOT NULL REFERENCES public.memos(id) ON DELETE CASCADE,
space_id UUID NOT NULL REFERENCES public.spaces(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ DEFAULT NOW(),
PRIMARY KEY (memo_id, space_id)
);
```
The schema includes foreign key constraints to ensure referential integrity between the spaces, memos, and user tables.
### API Integration
The app integrates with the Memoro API:
1. **API Endpoints**:
- `GET /api/memoro/spaces` - List all spaces for the authenticated user
- `GET /api/memoro/spaces/:id` - Get space details
- `POST /api/memoro/spaces` - Create a new space
- `PUT /api/memoro/spaces/:id` - Update a space
- `DELETE /api/memoro/spaces/:id` - Delete a space
- `GET /api/memoro/spaces/:spaceId/memos` - Get all memos for a specific space
- `POST /api/memoro/spaces/memos/link` - Link a memo to a space
- `DELETE /api/memoro/spaces/memos/unlink` - Unlink a memo from a space
### Space-Memo Relationship
Spaces can contain multiple memos, and memos can belong to multiple spaces. This is a many-to-many relationship implemented through the `memo_spaces` junction table. The API provides specific endpoints to manage these relationships:
- **Retrieving memos in a space**: Using `GET /api/memoro/spaces/:spaceId/memos`
- **Linking a memo to a space**: Using `POST /api/memoro/spaces/memos/link`
- **Unlinking a memo from a space**: Using `DELETE /api/memoro/spaces/memos/unlink`
### Data Structures
The Space interface reflects the updated API response structure:
```typescript
export interface Space {
id: string;
name: string;
description?: string;
memoCount?: number;
isDefault?: boolean;
color?: string;
created_at?: string;
updated_at?: string;
owner_id?: string;
app_id?: string;
credits?: number;
roles?: {
members: {
[userId: string]: {
role: string;
added_at: string;
added_by: string;
};
};
};
apps?: {
name: string;
slug: string;
};
}
```
And the Memo interface for space-specific memos:
```typescript
export interface Memo {
id: string;
title: string;
user_id: string;
source?: any;
style?: any;
is_pinned?: boolean;
is_archived?: boolean;
is_public?: boolean;
metadata?: any;
created_at?: string;
updated_at?: string;
}
```
### Authentication
Custom JWT-based authentication is used throughout:
1. User authenticates with the Memoro middleware (mana-core)
2. JWT token contains a `sub` claim with the user ID
3. This token is used for all API requests
4. All API endpoints require a valid JWT token
### Client Implementation
The app uses:
- `spaceService.ts`: Service for space operations, including memo management
- `useSpaces.ts`: Hook for React components
- `SpaceContext.tsx`: Context provider for the app
- `SpacesScreen.tsx`: Main UI for space management
- `[id].tsx`: Space detail view showing space info and all associated memos
## User Interface
The Spaces UI includes:
### Spaces List Screen
- List of spaces with customizable colors
- Create/edit/delete functionality
- Space selection for filtering memos
- Visual indication of the active space
### Space Detail Screen
- Shows space details (name, description, color, etc.)
- Displays all memos associated with the space
- Supports adding new memos to the space
- Handles error cases gracefully with retry mechanisms
## Error Handling
The system handles several error cases:
- Network failures during API requests
- Authentication errors
- Permission issues
- Database constraints
Error handling improvements:
- Error messages are properly displayed in the UI
- Retry mechanisms for failed requests
- Cleanup functions to prevent memory leaks and state updates after component unmount
- Mock data support for development/testing
### Error Handling Example
The Space detail view implements robust error handling:
```typescript
// Error handling for memo loading
useEffect(() => {
// Create a flag to prevent state updates after unmount
let isMounted = true;
const fetchSpaceMemos = async () => {
if (!id) return;
try {
setLoadingMemos(true);
setMemosError(null);
// Fetch memos for this space
const memos = await spaceContext.getSpaceMemos(id);
// Only update state if component is still mounted
if (isMounted) {
setSpaceMemos(memos);
}
} catch (err) {
console.error('Error fetching space memos:', err);
// Only update state if component is still mounted
if (isMounted) {
setMemosError('Failed to load memos for this space');
}
} finally {
// Only update state if component is still mounted
if (isMounted) {
setLoadingMemos(false);
}
}
};
fetchSpaceMemos();
// Cleanup function to prevent state updates after unmount
return () => {
isMounted = false;
};
}, [id]);
```
UI for error states:
```jsx
{loadingMemos ? (
<LoadingIndicator />
) : memosError ? (
<ErrorView
message={memosError}
onRetry={() => {
setLoadingMemos(true);
setMemosError(null);
// Re-render triggers the useEffect again
}}
/>
) : (
<MemoList memos={spaceMemos} spaceId={id} />
)}
```
## Development and Testing Support
The implementation includes development aids:
```typescript
// Mock data support for development
async getSpaceMemos(spaceId: string): Promise<Memo[]> {
// For development/testing, use mock data if API is not available
const USE_MOCK_DATA = process.env.EXPO_PUBLIC_USE_MOCK_DATA === 'true';
if (USE_MOCK_DATA) {
console.debug('Using mock data for space memos');
return [];
}
// Regular API call implementation
// ...
}
```
## Navigation
Navigation between spaces-related screens:
- From spaces list to space detail view via `router.push(`/(protected)/(space)/${spaceId}`)`
- Add memo to space via navigation to memo creation with space ID in params
- Back to spaces list via built-in back navigation
## Future Enhancements
Potential improvements for the spaces feature:
1. **Offline Support**: Caching space data for offline use
2. **Batch Operations**: Moving multiple memos between spaces
3. **Advanced Filtering**: Filter memos by multiple spaces or other criteria
4. **Space Sharing**: Allowing users to share spaces with other users
5. **Nested Spaces**: Implementing hierarchical space organization
## Maintenance and Troubleshooting
Common issues and solutions:
1. **API Communication Errors**: Check console logs for detailed error messages
2. **Authentication Issues**: Verify JWT token format and claims
3. **Performance Concerns**: Monitor API call performance
4. **Mock Data**: Use `EXPO_PUBLIC_USE_MOCK_DATA=true` for testing without API