# Design Document: Custom Start Page Application ## Overview The Custom Start Page Application is a web-based dashboard that provides users with a personalized starting point for their browsing sessions. The application follows a hypermedia-driven architecture using HTMX for dynamic interactions, with server-side HTML rendering and a Go backend. The system is designed to scale efficiently to support users with thousands of bookmarks and notes, with rich tagging, grouping, and content formatting capabilities. ### Requirements Coverage Summary This design document comprehensively addresses all requirements from the requirements document: **Authentication (Requirement 1):** OAuth-based authentication with Google and extensible provider support, session management, and secure logout. **Page Management (Requirement 2):** Multi-page dashboard with default "Home" page, page creation/deletion/reordering, and prevention of last page deletion. **Search Functionality (Requirement 3):** Customizable search providers (Google, DuckDuckGo, Bing) with persistent preferences and empty query validation. **Bookmark Widget (Requirement 4):** Full bookmark management with tags, groups, reordering, and efficient storage for 10,000+ bookmarks per user. Tag-based filtering with one-to-many relationships. **Notes Widget (Requirement 5):** Rich content support with multiple formats (plain text, RTF, code, YAML, Markdown), syntax highlighting, Unicode support, tag-based filtering, and format preservation. **Weather Widget (Requirement 6):** Location-based weather display with error handling and periodic refresh. **Widget Management (Requirement 7):** Widget creation, deletion, positioning, resizing, and custom titles with immediate persistence. **Data Persistence (Requirement 8):** Immediate persistence of all changes, DynamoDB-based storage optimized for 10,000+ items, efficient tag queries, and concurrent update handling. **Responsive Design (Requirement 9):** Adaptive layouts for desktop, tablet, and mobile with automatic reflow. **User Interface (Requirement 10):** Intuitive navigation with toolbar, page tabs, visual feedback, and loading indicators. **Database Evaluation (Requirement 11):** Comprehensive DynamoDB evaluation with analysis of scale handling, tag queries, concurrent updates, cost implications, indexing strategy, and alternative considerations. The application architecture emphasizes: - **Simplicity**: Server-side rendering with HTMX for dynamic updates, minimizing client-side complexity - **Separation of concerns**: Clear boundaries between UI templates, business logic, and data layers - **Extensibility**: Widget system designed to easily accommodate new widget types - **Real-time persistence**: All user changes are immediately saved to prevent data loss - **Responsive design**: Adaptive layouts that work across desktop, tablet, and mobile devices - **Scalability**: Efficient data models and access patterns to support 10,000+ bookmarks/notes per user - **Rich content support**: Multiple content formats with syntax highlighting and format-aware rendering - **Flexible organization**: Tag-based filtering and group-based organization for efficient content management ### Key Design Decisions **Architecture Pattern: Hypermedia-Driven with HTMX** The application uses HTMX for dynamic interactions, allowing server-side HTML rendering with minimal JavaScript. This approach provides: - Simplified frontend with no complex state management - Progressive enhancement (works without JavaScript) - Reduced bundle size and faster initial load - Server-side rendering for better SEO and accessibility - HTMX attributes for dynamic updates (hx-get, hx-post, hx-swap) **Database Selection: DynamoDB** After evaluating requirements for scale (10,000+ items), tag-based queries, and concurrent updates, DynamoDB is selected as the primary data store. This decision is based on: - Horizontal scalability for large item collections - Flexible schema for widget-specific configurations - Global Secondary Indexes (GSI) for efficient tag queries - Optimistic locking for concurrent update handling - Cost-effective at scale with on-demand pricing - Managed service reducing operational overhead **Backend Language: Go (with Python for specific tasks)** Go is the primary backend language, with Python used where Go is insufficient: - Go: HTTP server, routing, authentication, CRUD operations, DynamoDB access, HTML templating - Python: Weather API integration (if complex parsing needed), potential future ML features - Go's concurrency model handles multiple user requests efficiently - Go's standard library provides robust HTTP and template support **Scalability Architecture** The application is designed to scale efficiently to support users with 10,000+ bookmarks and notes. This addresses Requirements 4.13, 5.14, 8.8, 11.2. **Horizontal Scaling:** - Stateless Go backend servers (can run multiple instances behind load balancer) - Session state stored in DynamoDB or Redis (not in server memory) - No server affinity required (any server can handle any request) - Auto-scaling based on CPU/memory metrics **Database Scaling:** - DynamoDB on-demand capacity (automatic scaling) - Partition key design (user_id) ensures even data distribution - GSIs for efficient tag queries without full table scans - Batch operations for bulk reads/writes - Connection pooling for DynamoDB client **Caching Strategy:** - Redis cache for frequently accessed data (user preferences, tag lists) - Cache invalidation on updates - TTL-based expiration for weather data - Client-side caching with ETags for static assets **Performance Optimizations:** - Lazy loading for large bookmark/note lists (pagination or infinite scroll) - Debounced auto-save for notes (500ms delay) - Batch DynamoDB operations where possible - Compressed responses (gzip) - CDN for static assets (CSS, JS, images) **Data Access Patterns:** - Optimized for user-scoped queries (all data partitioned by user_id) - Minimal cross-user queries (only for sharing) - Denormalized data to avoid joins - Composite sort keys for efficient range queries **Load Testing Targets:** - 1,000 concurrent users - 10,000 bookmarks per user (p95 query time <100ms) - 100 requests/second per server instance - <200ms p95 latency for all operations - <2 seconds for tag deletion from 1,000 items **Validates Requirements 4.13, 5.14, 8.8, 11.2** **Tag Architecture** Tags are implemented as a many-to-many relationship using a dedicated TagAssociation table with GSIs for efficient bidirectional queries. This design addresses Requirements 4.9, 4.10, 4.14, 4.15, 5.12, 5.13, 5.15, 5.16, and 11.6. **Key Design Decisions:** - **Separate TagAssociations Table:** Avoids item size limits and enables efficient tag queries - **Normalized Tag Names:** All tags stored lowercase and trimmed for consistency - **Bidirectional GSIs:** Query items by tag (TagItemsIndex) and tags by item (primary key) - **Optimistic Locking:** Version numbers on items prevent concurrent update conflicts - **Atomic Operations:** TransactWriteItems ensures tag additions/removals are atomic **Capabilities:** - One-to-many relationships (multiple tags per bookmark/note) - Efficient tag-based filtering with O(log n) query complexity - Quick tag management operations (add, remove, rename, delete) - Tag usage statistics and autocomplete - Concurrent tag updates without data loss - Multi-tag filtering with AND/OR logic (computed in application layer) **Performance Characteristics:** - Single tag query: <10ms for 10,000 bookmarks - Multi-tag query (2 tags, AND): <50ms for 10,000 bookmarks - Tag addition: <20ms (transaction with version check) - Tag deletion from all items: ~2-3 seconds for 1,000 items (with progress indicator) **Validates Requirements 4.9, 4.10, 4.14, 4.15, 5.12, 5.13, 5.15, 5.16, 8.9, 8.10, 11.6, 11.7** **Rich Text Strategy** Notes support multiple content format modes (plain text, RTF, code, YAML, Markdown) with format-aware rendering. This design addresses Requirements 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.11, 5.18. **Content Format Modes:** 1. **Plain Text:** Simple text with line breaks and Unicode support 2. **Rich Text (RTF):** Basic formatting (bold, italic, lists, headings) using contenteditable or TinyMCE 3. **Code:** Syntax-highlighted code blocks with language selection (JavaScript, Python, Go, etc.) 4. **YAML:** Structured data with indentation preservation 5. **Markdown:** Markdown syntax with live preview **Storage Strategy:** - Content stored as string in DynamoDB Notes table - Format metadata stored in `format` field (enum: plain, rtf, code, yaml, markdown) - Language metadata stored in `language` field (for code format) - Raw content always preserved regardless of format - Format switching never loses data (raw content remains unchanged) **Rendering Strategy:** - **Plain Text:** Render in `
` or `
```

#### Client-Side JavaScript (Minimal)

**Sortable.js for Drag-and-Drop:**
- Initialize sortable on widget grid
- Initialize sortable on bookmark lists
- Send reorder requests via HTMX after drop

**Prism.js for Syntax Highlighting:**
- Automatically highlight code blocks
- Support multiple languages
- Apply on page load and after HTMX swaps

**CodeMirror (Optional):**
- Rich code editor for notes in code mode
- Syntax highlighting and line numbers
- Auto-save integration with HTMX

**Alpine.js (Optional):**
- Minor client-side state (dropdowns, modals)
- Tag autocomplete
- Format selector for notes


### Backend Services (Go)

All backend services are implemented in Go, with clear separation of concerns.

#### 1. Authentication Service

**Interface:**
```go
type AuthService interface {
    // InitiateOAuth starts OAuth flow and returns redirect URL
    InitiateOAuth(provider string) (redirectURL string, err error)
    
    // HandleOAuthCallback processes OAuth callback and creates session
    HandleOAuthCallback(provider string, code string) (user *User, sessionToken string, err error)
    
    // ValidateSession validates session token and returns user
    ValidateSession(token string) (*User, error)
    
    // Logout invalidates session token
    Logout(token string) error
}
```

**Implementation Notes:**
- Use golang.org/x/oauth2 for OAuth flows
- Store session tokens in cookies (httponly, secure)
- Use gorilla/sessions or similar for session management
- Support Google OAuth initially, extensible for others

#### 2. Page Service

**Interface:**
```go
type PageService interface {
    // GetPages retrieves all pages for a user in display order
    GetPages(userID string) ([]*Page, error)
    
    // CreatePage creates a new page
    CreatePage(userID string, name string) (*Page, error)
    
    // UpdatePage updates page name or order
    UpdatePage(pageID string, updates *PageUpdate) (*Page, error)
    
    // DeletePage deletes page and all associated widgets
    DeletePage(pageID string) error
    
    // ReorderPages updates page display order
    ReorderPages(userID string, pageOrder []string) error
}
```

#### 3. Widget Service

**Interface:**
```go
type WidgetService interface {
    // GetWidgets retrieves all widgets for a page
    GetWidgets(pageID string) ([]*Widget, error)
    
    // CreateWidget creates new widget of specified type
    CreateWidget(pageID string, widgetType WidgetType, config map[string]interface{}) (*Widget, error)
    
    // UpdateWidget updates widget configuration, position, or content
    UpdateWidget(widgetID string, updates *WidgetUpdate) (*Widget, error)
    
    // DeleteWidget deletes widget and associated data
    DeleteWidget(widgetID string) error
}
```

#### 4. Bookmark Service

**Interface:**
```go
type BookmarkService interface {
    // GetBookmarks retrieves all bookmarks for a widget
    GetBookmarks(widgetID string) ([]*Bookmark, error)
    
    // CreateBookmark creates new bookmark
    CreateBookmark(widgetID string, bookmark *BookmarkInput) (*Bookmark, error)
    
    // UpdateBookmark updates bookmark properties (with optimistic locking)
    UpdateBookmark(bookmarkID string, updates *BookmarkUpdate) (*Bookmark, error)
    
    // DeleteBookmark deletes bookmark and tag associations
    DeleteBookmark(bookmarkID string) error
    
    // ReorderBookmarks updates bookmark order
    ReorderBookmarks(widgetID string, bookmarkOrder []string) error
    
    // GetBookmarksByTags queries bookmarks by tags
    GetBookmarksByTags(userID string, tags []string, logic FilterLogic) ([]*Bookmark, error)
}
```

#### 5. Notes Service

**Interface:**
```go
type NotesService interface {
    // GetNote retrieves note for a widget
    GetNote(widgetID string) (*Note, error)
    
    // UpdateNote updates note content, format, or tags (with optimistic locking)
    UpdateNote(widgetID string, updates *NoteUpdate) (*Note, error)
    
    // GetNotesByTags queries notes by tags
    GetNotesByTags(userID string, tags []string, logic FilterLogic) ([]*Note, error)
}
```

#### 6. Tag Service

**Interface:**
```go
type TagService interface {
    // GetTags retrieves all tags for a user with usage counts
    GetTags(userID string) ([]*TagInfo, error)
    
    // AddTagToItem creates tag association (uses transaction)
    AddTagToItem(itemID string, itemType ItemType, tagName string) error
    
    // RemoveTagFromItem removes tag association
    RemoveTagFromItem(itemID string, tagName string) error
    
    // DeleteTag removes tag from all user's items
    DeleteTag(userID string, tagName string) (affectedCount int, err error)
    
    // RenameTag updates all tag associations
    RenameTag(userID string, oldName string, newName string) error
    
    // GetTagSuggestions returns tags matching prefix for autocomplete
    GetTagSuggestions(userID string, prefix string) ([]string, error)
}
```

#### 7. Group Service

**Interface:**
```go
type GroupService interface {
    // GetGroups retrieves all groups for a bookmark widget
    GetGroups(widgetID string) ([]*Group, error)
    
    // CreateGroup creates new group
    CreateGroup(widgetID string, name string) (*Group, error)
    
    // UpdateGroup updates group name or order
    UpdateGroup(groupID string, updates *GroupUpdate) (*Group, error)
    
    // DeleteGroup deletes group (moves bookmarks to specified destination)
    DeleteGroup(groupID string, moveToGroupID *string) error
    
    // MoveBookmarkToGroup updates bookmark's group assignment
    MoveBookmarkToGroup(bookmarkID string, groupID *string) error
    
    // ReorderGroups updates group display order
    ReorderGroups(widgetID string, groupOrder []string) error
}
```

**Implementation Notes:**
- Groups are widget-scoped (each bookmark widget has its own groups)
- Bookmarks can be ungrouped (group_id is optional)
- Deleting a group requires specifying where to move bookmarks (another group or ungrouped)
- Group names can be duplicated within a widget (user's choice)
- Groups have an order field for display ordering

**Validates Requirements 4.11, 4.12**

#### 8. Sharing Service

**Interface:**
```go
type SharingService interface {
    // CreateShare creates shareable link
    CreateShare(userID string, itemID string, itemType ItemType, options *ShareOptions) (*ShareLink, error)
    
    // GetSharedItem retrieves shared item by share_id (increments access count)
    GetSharedItem(shareID string) (*SharedItem, error)
    
    // RevokeShare deletes share link
    RevokeShare(shareID string) error
    
    // GetUserShares lists all shares created by user
    GetUserShares(userID string) ([]*ShareInfo, error)
}

type ShareOptions struct {
    ExpiresAt *time.Time // Optional expiration
}

type ShareLink struct {
    ShareID   string
    URL       string // Full shareable URL (e.g., https://app.com/share/abc123)
    ExpiresAt *time.Time
}

type SharedItem struct {
    ItemType   ItemType
    Data       interface{} // Bookmark or Note
    OwnerEmail string      // Optional owner info
    CreatedAt  time.Time
}
```

**Implementation Notes:**
- Share IDs can be UUIDs or short codes (e.g., 8-character alphanumeric)
- Shared items are read-only (no editing by recipients)
- Access count is incremented atomically on each view
- Expired shares return 404 or "Share expired" message
- Shared notes preserve formatting (format field included in response)
- Shared bookmarks include title, URL, and optional favicon
- No authentication required to view shared items (public links)

**Security Considerations:**
- Share IDs should be cryptographically random (prevent guessing)
- Rate limiting on share access to prevent abuse
- Optional expiration for time-limited sharing
- Owner can revoke shares at any time
- Shared content is sanitized to prevent XSS

**Validates Requirements 4.16, 5.17**

#### 9. Storage Service (DynamoDB)

**Interface:**
```go
type StorageService interface {
    // DynamoDB operations wrapper
    GetItem(tableName string, key map[string]interface{}) (map[string]interface{}, error)
    PutItem(tableName string, item map[string]interface{}) error
    UpdateItem(tableName string, key map[string]interface{}, updates map[string]interface{}) error
    DeleteItem(tableName string, key map[string]interface{}) error
    Query(tableName string, keyCondition string, params map[string]interface{}) ([]map[string]interface{}, error)
    TransactWrite(items []*TransactWriteItem) error
    BatchGet(requests []*BatchGetRequest) ([]map[string]interface{}, error)
}
```

**Implementation Notes:**
- Use aws-sdk-go-v2 for DynamoDB operations
- Implement retry logic with exponential backoff
- Handle conditional writes for optimistic locking
- Use transactions for multi-item consistency

#### 10. Weather Service (Python or Go)

**Interface:**
```go
type WeatherService interface {
    // GetWeather fetches current weather from external API
    GetWeather(location string) (*WeatherData, error)
    
    // ValidateLocation validates location string
    ValidateLocation(location string) (bool, error)
}
```

**Implementation Notes:**
- Can be implemented in Go using net/http
- Use Python if complex parsing or ML needed
- Cache results for rate limiting
- Handle API errors gracefully


### HTTP Endpoints (HTMX-Friendly)

All endpoints return HTML fragments or full pages (not JSON), designed for HTMX consumption.

**Authentication:**
- `GET /login` - Display login page
- `GET /auth/oauth/:provider` - Initiate OAuth flow
- `GET /auth/callback/:provider` - OAuth callback handler
- `POST /logout` - Logout user (returns redirect)
- `GET /auth/me` - Get current user info (for debugging)

**Pages:**
- `GET /dashboard` - Main dashboard page (full page)
- `GET /pages/:id` - Get widgets for page (HTML fragment for widget grid)
- `POST /pages` - Create new page (returns updated page tabs HTML)
- `PUT /pages/:id` - Update page (returns updated page tab HTML)
- `DELETE /pages/:id` - Delete page (returns updated page tabs HTML)
- `POST /pages/reorder` - Reorder pages (returns updated page tabs HTML)

**Widgets:**
- `GET /widgets/:id` - Get single widget HTML
- `POST /pages/:pageId/widgets` - Create widget (returns widget HTML)
- `PUT /widgets/:id` - Update widget (returns updated widget HTML)
- `DELETE /widgets/:id` - Delete widget (returns empty or success message)
- `POST /widgets/:id/position` - Update widget position (returns success)

**Bookmarks:**
- `GET /widgets/:widgetId/bookmarks` - Get bookmarks HTML for widget
- `POST /widgets/:widgetId/bookmarks` - Create bookmark (returns bookmark HTML)
- `PUT /bookmarks/:id` - Update bookmark (returns updated bookmark HTML)
- `DELETE /bookmarks/:id` - Delete bookmark (returns empty)
- `POST /bookmarks/reorder` - Reorder bookmarks (returns success)
- `GET /bookmarks/filter?tags=tag1,tag2&logic=and` - Filter by tags (returns filtered bookmarks HTML)

**Notes:**
- `GET /widgets/:widgetId/note` - Get note HTML for widget
- `POST /widgets/:widgetId/note` - Update note (returns save status HTML)
- `GET /notes/filter?tags=tag1,tag2&logic=and` - Filter by tags (returns filtered notes HTML)

**Tags:**
- `GET /tags` - Get all user tags (returns tag list HTML)
- `POST /items/:itemId/tags` - Add tag to item (returns updated tag list HTML)
- `DELETE /items/:itemId/tags/:tagName` - Remove tag (returns updated tag list HTML)
- `DELETE /tags/:tagName` - Delete tag from all items (returns success message)
- `PUT /tags/:oldName/rename` - Rename tag (returns success)
- `GET /tags/suggest?prefix=:prefix` - Get tag suggestions (returns datalist HTML)

**Groups:**
- `GET /widgets/:widgetId/groups` - Get groups HTML for widget
- `POST /widgets/:widgetId/groups` - Create group (returns group HTML)
- `PUT /groups/:id` - Update group (returns updated group HTML)
- `DELETE /groups/:id` - Delete group (returns success)
- `POST /bookmarks/:id/move` - Move bookmark to group (returns updated bookmark HTML)

**Sharing:**
- `POST /share` - Create share link (returns share dialog HTML with link)
- `GET /share/:shareId` - Get shared item (public, full page)
- `DELETE /share/:shareId` - Revoke share (returns success)
- `GET /shares` - Get user's shares (returns shares list HTML)

**Preferences:**
- `GET /preferences` - Get preferences form (returns form HTML)
- `POST /preferences` - Update preferences (returns success message)

**Weather:**
- `GET /weather?location=:location` - Get weather HTML for location

**Response Format:**
- All endpoints return HTML (full pages or fragments)
- Success responses return the updated HTML to swap
- Error responses return error message HTML with appropriate styling
- Use HTTP status codes: 200 (success), 400 (validation error), 401 (unauthorized), 404 (not found), 500 (server error)


## Data Models

### User Model
```typescript
User {
  id: string; // UUID
  email: string;
  oauth_provider: string;
  oauth_id: string;
  created_at: number; // Unix timestamp
  updated_at: number;
}
```

### Page Model
```typescript
Page {
  id: string; // UUID
  user_id: string;
  name: string;
  order: number;
  created_at: number;
  updated_at: number;
}
```

### Widget Model
```typescript
Widget {
  id: string; // UUID
  page_id: string;
  user_id: string;
  type: WidgetType; // 'bookmark' | 'notes' | 'weather'
  title?: string; // Optional custom title
  position: Position;
  size: Size;
  config: WidgetConfig; // Type-specific configuration
  created_at: number;
  updated_at: number;
}

Position {
  x: number;
  y: number;
}

Size {
  width: number;
  height: number;
}
```

### Bookmark Model
```typescript
Bookmark {
  id: string; // UUID
  widget_id: string;
  user_id: string;
  title: string;
  url: string;
  group_id?: string; // Optional group assignment
  order: number; // Order within widget or group
  favicon_url?: string;
  created_at: number;
  updated_at: number;
  version: number; // For optimistic locking
}
```

### Note Model
```typescript
Note {
  id: string; // UUID
  widget_id: string;
  user_id: string;
  title?: string;
  content: string;
  content_location: string; // 'dynamodb' | 's3://bucket/key'
  format: ContentFormat; // 'plain' | 'rtf' | 'code' | 'yaml' | 'markdown'
  language?: string; // For code format (e.g., 'javascript', 'python')
  created_at: number;
  updated_at: number;
  version: number; // For optimistic locking
}

ContentFormat = 'plain' | 'rtf' | 'code' | 'yaml' | 'markdown';
```

### Tag Association Model
```typescript
TagAssociation {
  item_id: string; // bookmark_id or note_id
  tag_name: string; // Normalized (lowercase, trimmed)
  user_id: string;
  item_type: ItemType; // 'bookmark' | 'note'
  created_at: number;
}

ItemType = 'bookmark' | 'note';
```

### Tag Info Model
```typescript
TagInfo {
  name: string;
  count: number; // Number of items with this tag
  item_types: ItemType[]; // Which types use this tag
}
```

### Group Model
```typescript
Group {
  id: string; // UUID
  widget_id: string;
  user_id: string;
  name: string;
  order: number;
  created_at: number;
  updated_at: number;
}
```

### Share Model
```typescript
Share {
  id: string; // UUID or short code
  user_id: string; // Owner
  item_id: string;
  item_type: ItemType;
  created_at: number;
  expires_at?: number; // Optional expiration
  access_count: number;
}

ShareLink {
  share_id: string;
  url: string; // Full shareable URL
  expires_at?: number;
}

SharedItem {
  item_type: ItemType;
  data: Bookmark | Note; // The actual item data
  owner_email?: string; // Optional owner info
}
```

### Preferences Model
```typescript
Preferences {
  user_id: string;
  search_provider: string; // 'google' | 'duckduckgo' | 'bing'
  theme?: string; // Optional theme preference
  updated_at: number;
}
```

### Widget Config Types

```typescript
BookmarkWidgetConfig {
  // No additional config needed at widget level
  // Bookmarks are stored in separate table
}

NotesWidgetConfig {
  // No additional config needed at widget level
  // Note is stored in separate table
}

WeatherWidgetConfig {
  location: string;
}
```


## 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.*

### Authentication Properties

**Property 1: Unauthenticated users see login page**
*For any* unauthenticated user state, the rendered application should display a login page containing OAuth provider options.
**Validates: Requirements 1.1**

**Property 2: OAuth provider selection triggers redirect**
*For any* available OAuth provider, selecting it should generate a redirect to that provider's authorization URL with correct parameters.
**Validates: Requirements 1.2, 1.6**

**Property 3: Successful OAuth creates or retrieves user**
*For any* valid OAuth authorization response, the authentication system should either create a new user account or retrieve an existing one, and return a valid session token.
**Validates: Requirements 1.3**

**Property 4: Failed OAuth shows error**
*For any* invalid OAuth authorization response, the authentication system should display an error message and return to the unauthenticated state.
**Validates: Requirements 1.4**

**Property 5: Session persistence across refresh**
*For any* authenticated user session, refreshing the application should preserve the authentication state and user data.
**Validates: Requirements 1.7**

**Property 6: Logout terminates session**
*For any* authenticated session, logging out should invalidate the session token and return the application to the unauthenticated state.
**Validates: Requirements 1.8**

### Page Management Properties

**Property 7: New users get default page**
*For any* newly created user account, the page list should contain exactly one page named "Home".
**Validates: Requirements 2.1**

**Property 8: Adding page increases count**
*For any* existing page list, adding a new page should increase the page count by exactly one.
**Validates: Requirements 2.2**

**Property 9: Page switching displays correct widgets**
*For any* page with associated widgets, switching to that page should display exactly those widgets and no others.
**Validates: Requirements 2.4**

**Property 10: Page deletion removes page and widgets**
*For any* page with associated widgets, deleting the page should remove both the page and all its widgets from the system.
**Validates: Requirements 2.5**

**Property 11: Page reordering persists**
*For any* page list and any valid reordering, applying the reorder should result in the new order being reflected in subsequent retrievals.
**Validates: Requirements 2.7**

### Search Properties

**Property 12: Search generates correct URL**
*For any* non-empty search query and configured search provider, submitting the search should generate the correct search URL for that provider.
**Validates: Requirements 3.2**

**Property 13: Search provider selection persists**
*For any* available search provider, selecting it should update the user's preferences and persist the change across sessions.
**Validates: Requirements 3.4**

**Property 14: Empty search is rejected**
*For any* string composed entirely of whitespace characters, submitting it as a search query should not trigger a search action.
**Validates: Requirements 3.7**

### Widget Management Properties

**Property 15: Widget creation increases count**
*For any* page and any widget type, creating a widget should increase that page's widget count by exactly one.
**Validates: Requirements 4.1, 5.1, 6.1, 7.2**

**Property 16: Widget deletion decreases count**
*For any* page with widgets, deleting a widget should decrease the page's widget count by exactly one and remove that specific widget.
**Validates: Requirements 7.3**

**Property 17: Widget position updates persist**
*For any* widget and any valid position, updating the widget's position should persist the change and reflect it in subsequent retrievals.
**Validates: Requirements 7.5**

**Property 18: Widget IDs are unique**
*For any* set of widgets in the system, all widget IDs should be unique across all pages and users.
**Validates: Requirements 7.8**

**Property 19: Widget title customization**
*For any* widget and any custom title string, setting the custom title should update the widget and display the new title in the UI.
**Validates: Requirements 4.8, 5.10, 6.7**

### Bookmark Widget Properties

**Property 20: Bookmark addition persists**
*For any* bookmark widget and any valid bookmark (title and URL), adding the bookmark should store it and make it retrievable from the widget's bookmark list.
**Validates: Requirements 4.2**

**Property 21: Bookmark editing updates values**
*For any* bookmark in a widget, editing its title, URL, or tags should update the stored values and reflect the changes in subsequent retrievals.
**Validates: Requirements 4.4**

**Property 22: Bookmark deletion removes from list**
*For any* bookmark in a widget, deleting it should remove it from the widget's bookmark list and decrease the bookmark count by one.
**Validates: Requirements 4.5**

**Property 23: Bookmark reordering persists**
*For any* bookmark list and any valid reordering, applying the reorder should result in the new order being reflected in subsequent retrievals.
**Validates: Requirements 4.6**

**Property 24: Bookmark rendering includes all titles**
*For any* bookmark widget with bookmarks, the rendered output should contain all bookmark titles in the correct order.
**Validates: Requirements 4.7**

**Property 25: Group creation and assignment**
*For any* bookmark widget, creating a group and assigning bookmarks to it should persist the group structure and allow retrieval of bookmarks by group.
**Validates: Requirements 4.11**

**Property 26: Bookmark group reassignment**
*For any* bookmark and any target group (or ungrouped), moving the bookmark should update its group assignment and persist the change.
**Validates: Requirements 4.12**

### Notes Widget Properties

**Property 27: Notes content persists**
*For any* notes widget and any text content, updating the content should save it and make it retrievable in subsequent retrievals.
**Validates: Requirements 5.2, 5.9**

**Property 28: Content format preservation**
*For any* note with content in a specific format (plain, RTF, code, YAML, Markdown), saving and retrieving the note should preserve both the content and format metadata.
**Validates: Requirements 5.4, 5.11**

**Property 29: Unicode content preservation**
*For any* text content containing Unicode characters (international text, emoji), saving to a notes widget and retrieving it should preserve all Unicode characters correctly.
**Validates: Requirements 5.5**

**Property 30: Format switching preserves content**
*For any* note content and any format mode switch, changing the format mode should preserve the raw content without data loss.
**Validates: Requirements 5.18**

**Property 31: Code syntax highlighting**
*For any* note in code format with a specified language, the rendered output should include syntax highlighting appropriate for that language.
**Validates: Requirements 5.6**

**Property 32: YAML indentation preservation**
*For any* YAML content with indentation, saving and retrieving the content should preserve all indentation and structure.
**Validates: Requirements 5.7**

**Property 33: RTF formatting preservation**
*For any* rich text content with formatting (bold, italic, lists, headings), saving and retrieving should preserve all formatting.
**Validates: Requirements 5.8**

### Tag System Properties

**Property 34: Tag association supports one-to-many**
*For any* item (bookmark or note) and any set of tags, adding multiple tags should create all associations and make them retrievable.
**Validates: Requirements 4.9, 5.12**

**Property 35: Tag filtering returns matching items**
*For any* tag filter (single or multiple tags), querying items by tags should return only items that match the filter criteria.
**Validates: Requirements 4.10, 5.13, 8.9**

**Property 36: Tag deletion removes from all items**
*For any* tag name, deleting the tag should remove it from all associated bookmarks and notes.
**Validates: Requirements 4.15, 5.16**

**Property 37: Concurrent tag updates preserve data**
*For any* item and any concurrent tag update operations, all tag changes should be preserved without data loss or corruption.
**Validates: Requirements 4.14, 5.15, 8.10**

### Sharing Properties

**Property 38: Share link generation**
*For any* item (bookmark or note), creating a share should generate a unique shareable link that allows read-only access to the item.
**Validates: Requirements 4.16, 5.17**

**Property 39: Shared note preserves formatting**
*For any* note with formatting, accessing it via a share link should display the content with the original format preserved.
**Validates: Requirements 5.17**

### Weather Widget Properties

**Property 40: Weather data fetching**
*For any* valid location string, the weather widget should fetch weather data and display temperature, condition description, and an icon.
**Validates: Requirements 6.2, 6.3**

**Property 41: Weather location updates**
*For any* weather widget with a location, changing to a different valid location should fetch and display weather data for the new location.
**Validates: Requirements 6.4**

**Property 42: Weather error handling**
*For any* invalid location or API failure condition, the weather widget should display an error message instead of weather data.
**Validates: Requirements 6.5**

### Data Persistence Properties

**Property 43: Immediate persistence**
*For any* user action that modifies data (pages, widgets, bookmarks, notes, preferences, tags), the change should be immediately persisted and retrievable without requiring additional save actions.
**Validates: Requirements 2.8, 7.7, 8.1**

**Property 44: Data round-trip consistency**
*For any* user's complete data state (pages, widgets, bookmarks, notes, tags, groups, preferences), saving the state, logging out, and logging back in should restore an equivalent state.
**Validates: Requirements 8.2, 8.3, 8.4, 8.5**

**Property 45: Data isolation**
*For any* two different users, each user's data should be accessible only to that user and not visible or modifiable by the other user.
**Validates: Requirements 8.7**

**Property 46: Storage error handling**
*For any* storage operation failure, the application should display an error message to the user and maintain the previous valid state.
**Validates: Requirements 8.6**

### User Interface Properties

**Property 47: Interactive element feedback**
*For any* interactive element (button, link, input), hovering or clicking should trigger a visual state change.
**Validates: Requirements 10.4**

**Property 48: Action confirmation feedback**
*For any* user action (create, delete, update), the application should provide immediate visual confirmation that the action was performed.
**Validates: Requirements 10.5**

**Property 49: Loading indicators**
*For any* asynchronous operation (API call, data fetch), the application should display a loading indicator while the operation is in progress.
**Validates: Requirements 10.7**

**Property 50: Responsive layout reflow**
*For any* viewport size change, the application should reflow the layout to match the new dimensions without requiring a page refresh.
**Validates: Requirements 9.5**


## Error Handling

### Authentication Errors

**OAuth Failures:**
- Invalid authorization codes should return clear error messages
- Network failures during OAuth should be caught and displayed to users
- Expired or invalid session tokens should redirect to login

**Session Management:**
- Expired sessions should be detected and handled gracefully
- Concurrent session conflicts should be resolved (last-write-wins or error)
- Token validation failures should clear local state and redirect to login

### Data Validation Errors

**Input Validation:**
- Empty or whitespace-only strings should be rejected for required fields
- Invalid URLs in bookmarks should be caught and reported
- Invalid location strings for weather should show helpful error messages
- Page names should have length limits (1-50 characters) and character restrictions (no special chars)
- Tag names should be normalized (lowercase, trimmed) and validated for length (1-30 characters)
- **Validates Requirements 2.3, 4.2, 6.2**

**Data Integrity:**
- Attempts to delete non-existent resources should return 404 errors
- Attempts to modify resources owned by other users should return 403 errors
- Malformed widget configurations should be rejected with validation errors
- Version conflicts in optimistic locking should trigger retry logic
- **Validates Requirements 8.7, 8.10**

**Page Management:**
- Attempts to delete the last remaining page should be prevented
- Error message: "Cannot delete the last page. You must have at least one page."
- UI should disable delete button when only one page remains
- **Validates Requirement 2.6**

### Tag System Errors

**Tag Operations:**
- Duplicate tag additions should be idempotent (no error, no duplicate)
- Tag name conflicts during rename should be detected and reported
- Concurrent tag updates should use optimistic locking to prevent lost updates
- Tag deletion should handle cases where tag doesn't exist gracefully

**Tag Queries:**
- Empty tag filter should return all items (no filtering)
- Non-existent tags in filter should return empty results
- Malformed tag queries should return validation errors

### Group System Errors

**Group Operations:**
- Duplicate group names within a widget should be allowed (user's choice)
- Deleting a group with bookmarks should require user to specify destination
- Moving bookmark to non-existent group should return validation error
- Group order conflicts should be resolved by server

### Content Format Errors

**Format Validation:**
- Invalid format mode selection should default to plain text
- Unsupported language for code highlighting should use generic highlighting
- Malformed YAML should be stored as-is (no validation, user's responsibility)
- Malformed Markdown should be rendered as-is (marked.js handles gracefully)
- Format switching should never lose raw content data
- **Validates Requirements 5.3, 5.4, 5.18**

**Content Size:**
- Notes exceeding 400KB should be rejected with clear error message
- Alternative: Large notes (>100KB) could be automatically moved to S3 with reference in DynamoDB
- Threshold: Warn user at 50KB, auto-move to S3 at 100KB
- Bookmark URLs exceeding reasonable length (2KB) should be rejected
- **Validates Requirements 5.14, 11.2**

**Unicode and Special Characters:**
- All Unicode characters should be preserved (UTF-8 encoding throughout)
- Emoji should render correctly (system fonts or emoji library)
- International text (Chinese, Arabic, Cyrillic) should display correctly
- No character encoding issues (UTF-8 from browser to database)
- **Validates Requirement 5.5**

**Syntax Highlighting Errors:**
- Unknown language should fall back to generic highlighting
- Syntax errors in code should not prevent rendering
- Highlighting library failures should fall back to plain text display
- **Validates Requirement 5.6**

**RTF Formatting Errors:**
- Invalid HTML in RTF content should be sanitized (DOMPurify)
- XSS prevention: All user-generated HTML is sanitized
- Unsupported formatting should be stripped gracefully
- **Validates Requirement 5.8**

### External Service Errors

**Weather API Failures:**
- Network timeouts should show "Unable to fetch weather" message
- Invalid API keys should be logged server-side and show generic error to users
- Rate limiting should be handled with cached data or retry logic
- Invalid location responses should show "Location not found" message

**OAuth Provider Failures:**
- Provider downtime should show "Authentication service unavailable" message
- Network errors during OAuth flow should allow retry
- Provider-specific errors should be translated to user-friendly messages

### DynamoDB Errors

**Capacity Errors:**
- Throttling errors should trigger exponential backoff retry
- On-demand capacity should prevent most throttling issues
- Persistent throttling should be logged and monitored

**Consistency Errors:**
- Conditional write failures (version conflicts) should trigger retry with latest version
- Transaction failures should rollback and return error to user
- Batch operation partial failures should be handled item-by-item

**Connection Errors:**
- Network failures should trigger retry with exponential backoff
- Persistent connection issues should show "Service temporarily unavailable"
- Timeout errors should be caught and reported to user

### UI Error Handling

**User Feedback:**
- All errors should display user-friendly messages (not stack traces)
- Error messages should be dismissible
- Critical errors should prevent further actions until resolved
- Non-critical errors should allow users to continue working

**Recovery Mechanisms:**
- Failed operations should be retryable
- Partial failures should not corrupt existing data
- Auto-save failures should queue changes for retry
- Network errors should trigger automatic retry with exponential backoff
- Optimistic UI updates should rollback on server error

**Error Boundaries:**
- React error boundaries should catch component errors
- Widget errors should not crash entire dashboard
- Isolated widget failures should show error state in that widget only
- Global errors should show full-page error with reload option


## Testing Strategy

### Dual Testing Approach

The application will use both unit testing and property-based testing to ensure comprehensive coverage:

**Unit Tests:**
- Specific examples demonstrating correct behavior
- Edge cases and boundary conditions
- Integration points between components
- Error conditions and failure scenarios
- UI component rendering with specific props
- Specific format examples (YAML, Markdown, code)
- Specific tag operations (add, remove, filter)
- Group management operations

**Property-Based Tests:**
- Universal properties that hold for all inputs
- Comprehensive input coverage through randomization
- Invariants that must be maintained across operations
- Round-trip properties for serialization and data persistence
- Concurrent operation safety
- Tag system correctness across all operations
- Format preservation across all content types
- Minimum 100 iterations per property test

### Property-Based Testing Configuration

**Framework Selection:**
- **Go**: testing package (built-in) + testify for assertions
- **Go Property Testing**: gopter or rapid library
- **Python** (if used): pytest + Hypothesis

**Test Configuration:**
- Each property test must run minimum 100 iterations
- Each test must reference its design document property
- Tag format: `Feature: custom-start-page, Property {number}: {property_text}`
- Each correctness property must be implemented by a single property-based test

**Generator Strategy:**
- Create generators for all domain objects (User, Page, Widget, Bookmark, Note, Tag, Group)
- Generate valid and invalid inputs to test error handling
- Use shrinking to find minimal failing examples
- Ensure generators cover edge cases:
  - Empty lists and collections
  - Special characters and Unicode in text
  - Boundary values (max lengths, large counts)
  - Concurrent operations
  - Multiple tags per item
  - Multiple formats for notes
  - Large datasets (1000+ bookmarks for scale testing)

**Tag System Generators:**
- Generate random tag names (normalized and non-normalized)
- Generate items with 0 to 10 tags
- Generate tag filters (single tag, multiple tags, AND/OR logic)
- Generate concurrent tag operations

**Content Format Generators:**
- Generate plain text with various Unicode characters
- Generate RTF with formatting markers
- Generate code in various languages
- Generate valid and invalid YAML
- Generate Markdown with various elements
- Generate content at various sizes (small, medium, large)

### Testing Layers

**Frontend Testing:**
- HTML template rendering tests
- HTMX attribute validation
- Integration tests for user flows
- Visual regression tests for UI consistency
- Accessibility tests (WCAG compliance)
- Syntax highlighting tests
- Tag filter UI tests
- Drag-and-drop tests with Sortable.js

**Backend Testing (Go):**
- HTTP handler unit tests
- Service layer property tests
- DynamoDB integration tests
- OAuth flow integration tests
- Performance tests for data operations
- Concurrent update tests
- Tag query performance tests
- Batch operation tests
- Template rendering tests

**DynamoDB Testing:**
- Schema validation tests
- Access pattern tests (all 10 patterns)
- GSI query tests
- Optimistic locking tests
- Transaction tests
- Batch operation tests
- Cost estimation validation

**End-to-End Testing:**
- Critical user journeys:
  - Login → create page → add widgets → add bookmarks with tags
  - Create notes with different formats
  - Filter bookmarks/notes by tags
  - Create groups and organize bookmarks
  - Share bookmarks and notes
  - Concurrent tag updates from multiple sessions
- Cross-browser compatibility tests
- Mobile responsiveness tests
- Session persistence tests
- Large dataset tests (1000+ bookmarks)

### Test Coverage Goals

- Minimum 80% code coverage for business logic
- 100% coverage of error handling paths
- All correctness properties implemented as property tests
- All acceptance criteria covered by unit or property tests
- Integration tests for all HTTP endpoints
- All DynamoDB access patterns tested
- All tag operations tested for correctness and concurrency
- All content formats tested for preservation
- All HTML templates tested for correct rendering

### Performance Testing

**Scale Testing:**
- Test with 10,000+ bookmarks per user
- Test with 1,000+ notes per user
- Test with 100+ tags per user
- Test tag queries with large result sets
- Test concurrent updates with multiple sessions

**Benchmarks:**
- Page load time with 100 widgets
- Bookmark list rendering with 1,000 bookmarks
- Tag filter query time with 10,000 bookmarks
- Note editor performance with large content
- DynamoDB query latency for all access patterns

**Load Testing:**
- Concurrent user sessions
- Rapid tag updates
- Batch bookmark operations
- Weather API rate limiting
- DynamoDB throughput limits

### Continuous Integration

- Run all tests on every commit
- Property tests run with 100 iterations in CI
- Extended property test runs (1000+ iterations) nightly
- Performance benchmarks tracked over time
- Test failures block merges to main branch
- DynamoDB local for integration tests
- Mock external services (OAuth, Weather API)

### Test Data Management

**Fixtures:**
- Sample users with various data sizes
- Sample bookmarks with tags and groups
- Sample notes in all formats
- Sample tag associations
- Sample shared items

**Factories:**
- User factory with configurable OAuth provider
- Page factory with configurable widget count
- Widget factory for each type
- Bookmark factory with tags and groups
- Note factory with format selection
- Tag factory with normalization

**Cleanup:**
- Tear down test data after each test
- Use DynamoDB local for isolated testing
- Clear caches between tests
- Reset mock services