Nounspace Architecture Documentation
Space and Tab Management System
Overview
Nounspace features two distinct architectural patterns for space management: Public Spaces and Private Spaces (Homebase). While they share a common presentation layer through the SpacePage component, they differ significantly in state management, data flow, and tab handling.
Core Components
┌─────────────────────┐ ┌─────────────────────┐
│ Public Spaces │ │ Private Spaces │
│ (Server + Client) │ │ (Client) │
└─────────┬───────────┘ └──────────┬──────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ SpacePage │◄─────────►│ Zustand Store │
└─────────┬───────────┘ └─────────────────────┘
│
▼
┌─────────────────────┐
│ Space │
└─────────────────────┘
1. Public Spaces Architecture
Design Philosophy
Public spaces follow a server/client separation pattern with clear boundaries for data transmission. They implement a unified SpacePageData interface with type-specific extensions.
Key Components
Data Flow
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Page (Server) │────►│ Type Space (CL) │────►│ PublicSpace │
│ Loads Data │ │ Adds isEditable │ │ Renders UI │
└─────────────────┘ └─────────────────┘ └─────────────────┘
-
Server Components (
page.tsx)- Load space data without client-side functions
- Return
Omit<SpaceData, 'isEditable' | 'spacePageUrl'> - Handle 404 cases and initial data loading
-
Type-Specific Components (
ProfileSpace.tsx, etc.)- Add client-side
isEditablelogic based on space type - Add
spacePageUrlfunction for navigation - Pass complete data to
PublicSpace
- Add client-side
-
Common Component (
PublicSpace.tsx)- Handles space registration if needed
- Manages tab rendering and switching
- Coordinates state with Zustand store for edits
Tab Management
Public spaces store tabs as a simple string array within the space configuration:
interface SpaceConfig {
// ... other properties
tabNames?: string[]; // Array of tab names in order
}
Tab Creation Process
- Server loads initial tab configuration
- Client adds new tab to
config.tabNames - Updates are persisted through
saveConfigandcommitConfig
Tab Navigation
URLs follow predictable patterns based on space type:
- Profile:
/s/username/TabName - Token:
/t/network/address/TabName - Proposal:
/p/proposalId/TabName
2. Private Spaces (Homebase) Architecture
Design Philosophy
Private spaces use a client-side Zustand store with optimistic updates and synchronized local/remote state management.
Key Components
Data Flow
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Zustand Store │◄───►│ PrivateSpace │────►│ SpacePage │
│ State Source │ │ Loads/Updates │ │ Renders UI │
└─────────────────┘ └─────────────────┘ └─────────────────┘
-
Store Structure
homebaseStore.ts: Core state and actionshomebaseTabsStore.ts: Tab-specific logiccurrentSpace: Tracking and navigation
-
Tab Management
- Special handling for Feed tab
- Complex state synchronization
- Optimistic UI updates
Tab Management
Private spaces maintain separate structures for tab configuration and ordering:
interface HomeBaseTabStoreState {
tabs: {
[tabName: string]: {
config?: SpaceConfig; // Local tab configuration
remoteConfig?: SpaceConfig; // Last known server configuration
};
};
tabOrdering: {
local: string[]; // Current local order (possibly edited)
remote: string[]; // Last known server order
};
}
Tab Creation Process
- Create local tab configuration
- Update local tab ordering
- Commit both to database separately
- Manage optimistic updates and rollbacks
Tab Navigation
Uses clean URLs with special handling for the Feed tab:
- Feed:
/homebase - Other tabs:
/homebase/TabName
3. Storage System
Public Spaces
-
Supabase Tables:
spaceRegistrations: MapsspaceIdto owner information- Stores type-specific metadata (fid, contract address, etc.)
-
Supabase Storage:
- Path format:
spaces/${spaceId}/tabs/${tabName} - Tab order:
spaces/${spaceId}/tabOrder - JSON files with configuration data
- Path format:
-
API Routes:
/api/space/registry: Space registration/api/space/registry/${spaceId}/tabs: Tab management
Private Spaces
-
Supabase Storage:
- Path format:
private/${identityPublicKey}/tabs/${tabName} - Tab order:
private/${identityPublicKey}/tabOrder - Feed configuration:
private/${identityPublicKey}/homebase - Encrypted for privacy
- Path format:
-
API Routes:
/api/space/homebase: Feed configuration/api/space/homebase/tabs: Tab management
4. Architectural Differences
| Feature | Public Spaces | Private Spaces |
|---|---|---|
| State Management | Server + Client | Client-only Zustand |
| Tab Storage | Single tabNames array | Separate tabOrdering object |
| Default Tab | Type-specific ("Profile", "Token", etc.) | Always "Feed" |
| Data Flow | Unidirectional | Bidirectional with store |
| Type System | Strong interface inheritance | Loosely coupled store slices |
| Initialization | Server-side data loading | Client-side data fetching |
| Editability | Type-specific rules | Always editable by owner |
| URL Structure | Type-specific patterns | Homebase-specific pattern |
5. Common Infrastructure
Both architectures share common components:
- SpacePage: Renders spaces with consistent UI
- TabBar: Renders and manages tab interactions
- Space: Core layout and fidget rendering
- Authentication: Common authentication system
6. Development Guidelines
Working with Public Spaces
-
Add a New Public Space Type:
src/app/(spaces)/{type}/[param]/
├── page.tsx # Server-side data loading
├── utils.ts # Helper functions
├── {Type}Space.tsx # Client-side component
└── layout.tsx # Layout component -
Extending Space Data:
interface NewTypeSpaceData extends SpacePageData {
spaceType: typeof SPACE_TYPES.NEW_TYPE;
defaultTab: 'DefaultTabName';
// Type-specific properties
}
Working with Private Spaces
-
Modify Tab Behavior:
- Edit
homebaseTabsStore.tsfor tab management logic - Update
PrivateSpace.tsxfor tab rendering
- Edit
-
Add New Tab Actions:
- Add action to store
- Update UI components to trigger action
- Handle optimistic updates and error states
7. Future Architectural Considerations
For future development, consider:
-
Unified Space Data Model:
- Create a
HomebaseSpaceDatainterface extendingSpacePageData - Adapt PrivateSpace to construct this model from store
- Create a
-
Common Tab Management:
- Move tab ordering to a consistent location across space types
- Simplify TabBar to work with a unified tab interface
-
Improved Type Safety:
- Add stronger typing to Zustand store slices
- Create type guards for private spaces similar to public spaces
This architecture provides flexibility for different space types while maintaining consistent user experience through shared rendering components.