Browse Source

Enhanced contact import documentation and test cleanup

- Added comprehensive educational documentation to ContactImportView.vue explaining
  the contact import workflow, data processing pipeline, and UI components
- Enhanced ContactsView.vue with detailed documentation covering contact input
  workflow, bulk operations, and state management
- Cleaned up test-playwright/45-contact-import.spec.ts by removing debugging
  console logs and adding thorough documentation explaining how the contact
  import page works, including user workflow, page structure, and component
  interactions
- Fixed syntax errors in test file that were preventing test execution
- All 34 contact import tests now pass successfully with improved performance
  monitoring and error handling

The documentation now provides complete context for developers understanding
the contact import system from user perspective through technical implementation.
pull/159/head
Matthew Raymer 3 weeks ago
parent
commit
294034d9b4
  1. 172
      .cursor/rules/absurd-sql.mdc
  2. 280
      src/views/ContactImportView.vue
  3. 138
      src/views/ContactsView.vue
  4. 665
      test-playwright/45-contact-import.spec.ts

172
.cursor/rules/absurd-sql.mdc

@ -3,50 +3,50 @@ description:
globs: globs:
alwaysApply: true alwaysApply: true
--- ---
# Absurd SQL - Cursor Development Guide # Absurd SQL - Cursor Development Guide (Directive Style)
## Project Overview ## Project Overview
Absurd SQL is a backend implementation for sql.js that enables persistent SQLite databases in the browser by using IndexedDB as a block storage system. This guide provides rules and best practices for developing with this project in Cursor. Implement persistent SQLite databases in the browser using **Absurd SQL** with IndexedDB as block storage. Execute all SQL operations according to the following directives.
## Project Structure ## Project Structure
``` ```
absurd-sql/ absurd-sql/
├── src/ # Source code ├── src/ # Place source code here
├── dist/ # Built files ├── dist/ # Place built files here
├── package.json # Dependencies and scripts ├── package.json # Maintain dependencies and scripts here
├── rollup.config.js # Build configuration ├── rollup.config.js # Maintain build configuration here
└── jest.config.js # Test configuration └── jest.config.js # Maintain test configuration here
``` ```
## Development Rules ## Directives
### 1. Worker Thread Requirements ### 1. Worker Thread Execution
- All SQL operations MUST be performed in a worker thread - Execute **all SQL operations** inside worker threads.
- Main thread should only handle worker initialization and communication - Restrict the main thread to **initialization** and **communication only**.
- Never block the main thread with database operations - Block **no operations** on the main thread.
### 2. Code Organization ### 2. Code Organization
- Keep worker code in separate files (e.g., `*.worker.js`) - Store worker logic in dedicated files: `*.worker.js`.
- Use ES modules for imports/exports - Use **ES modules** exclusively.
- Follow the project's existing module structure - Conform to the existing **module structure**.
### 3. Required Headers ### 3. Headers Enforcement
When developing locally or deploying, ensure these headers are set: Always set the following headers:
``` ```
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp Cross-Origin-Embedder-Policy: require-corp
``` ```
### 4. Browser Compatibility ### 4. Browser Compatibility
- Primary target: Modern browsers with SharedArrayBuffer support - Target **modern browsers with SharedArrayBuffer support**.
- Fallback mode: Safari (with limitations) - Activate fallback mode for Safari when required.
- Always test in both modes - Test in **both primary and fallback modes** without exception.
### 5. Database Configuration ### 5. Database Configuration
Recommended database settings: Apply the following PRAGMA settings immediately:
```sql ```sql
PRAGMA journal_mode=MEMORY; PRAGMA journal_mode=MEMORY;
PRAGMA page_size=8192; -- Optional, but recommended PRAGMA page_size=8192;
``` ```
### 6. Development Workflow ### 6. Development Workflow
@ -54,100 +54,96 @@ PRAGMA page_size=8192; -- Optional, but recommended
```bash ```bash
yarn add @jlongster/sql.js absurd-sql yarn add @jlongster/sql.js absurd-sql
``` ```
2. Execute commands as follows:
2. Development commands: - `yarn build` → build the project
- `yarn build` - Build the project - `yarn jest` → run all tests
- `yarn jest` - Run tests - `yarn serve` → launch development server
- `yarn serve` - Start development server
### 7. Testing
### 7. Testing Guidelines - Write tests for both **SharedArrayBuffer** and **fallback modes**.
- Write tests for both SharedArrayBuffer and fallback modes - Use **Jest** exclusively.
- Use Jest for testing - Include **performance benchmarks** for critical paths.
- Include performance benchmarks for critical operations
### 8. Performance Optimization
### 8. Performance Considerations - Execute bulk operations when available.
- Use bulk operations when possible - Enforce **transactions** for multi-step operations.
- Monitor read/write performance - Monitor read/write throughput continuously.
- Consider using transactions for multiple operations - Reuse database connections. Do **not** open unnecessary ones.
- Avoid unnecessary database connections
### 9. Error Handling ### 9. Error Handling
- Implement proper error handling for: Implement error handling for:
- Worker initialization failures - Worker initialization failures
- Database connection issues - Database connection issues
- Concurrent access conflicts (in fallback mode) - Concurrent access conflicts (fallback mode)
- Storage quota exceeded scenarios - Storage quota exceeded scenarios
### 10. Security Best Practices ### 10. Security
- Never expose database operations directly to the client - Forbid direct client access to database operations.
- Validate all SQL queries - Validate every SQL query.
- Implement proper access controls - Enforce access control measures.
- Handle sensitive data appropriately - Handle sensitive data with strict isolation.
### 11. Code Style ### 11. Code Style
- Follow ESLint configuration - Follow ESLint configuration.
- Use async/await for asynchronous operations - Use `async/await` for asynchronous operations.
- Document complex database operations - Document complex operations thoroughly.
- Include comments for non-obvious optimizations - Comment all optimizations that are not obvious.
### 12. Debugging ### 12. Debugging
- Use `jest-debug` for debugging tests - Use `jest-debug` for test debugging.
- Monitor IndexedDB usage in browser dev tools - Inspect IndexedDB in browser developer tools.
- Check worker communication in console - Trace worker communication in console logs.
- Use performance monitoring tools - Apply browser performance monitoring tools.
## Common Patterns ## Required Patterns
### Worker Initialization ### Worker Initialization
```javascript ```javascript
// Main thread
import { initBackend } from 'absurd-sql/dist/indexeddb-main-thread'; import { initBackend } from 'absurd-sql/dist/indexeddb-main-thread';
function init() { function init() {
let worker = new Worker(new URL('./index.worker.js', import.meta.url)); const worker = new Worker(new URL('./index.worker.js', import.meta.url));
initBackend(worker); initBackend(worker);
} }
``` ```
### Database Setup ### Database Setup
```javascript ```javascript
// Worker thread
import initSqlJs from '@jlongster/sql.js'; import initSqlJs from '@jlongster/sql.js';
import { SQLiteFS } from 'absurd-sql'; import { SQLiteFS } from 'absurd-sql';
import IndexedDBBackend from 'absurd-sql/dist/indexeddb-backend'; import IndexedDBBackend from 'absurd-sql/dist/indexeddb-backend';
async function setupDatabase() { async function setupDatabase() {
let SQL = await initSqlJs({ locateFile: file => file }); const SQL = await initSqlJs({ locateFile: f => f });
let sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend()); const sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend());
SQL.register_for_idb(sqlFS); SQL.register_for_idb(sqlFS);
SQL.FS.mkdir('/sql'); SQL.FS.mkdir('/sql');
SQL.FS.mount(sqlFS, {}, '/sql'); SQL.FS.mount(sqlFS, {}, '/sql');
return new SQL.Database('/sql/db.sqlite', { filename: true }); return new SQL.Database('/sql/db.sqlite', { filename: true });
} }
``` ```
## Troubleshooting ## Troubleshooting Directives
### Common Issues ### If SharedArrayBuffer is unavailable:
1. SharedArrayBuffer not available - Verify COOP/COEP headers.
- Check COOP/COEP headers - Check browser support.
- Verify browser support - Activate fallback mode.
- Test fallback mode
### If worker initialization fails:
2. Worker initialization failures - Verify file paths.
- Check file paths - Confirm module imports.
- Verify module imports - Inspect browser console for errors.
- Check browser console for errors
### If performance degrades:
3. Performance issues - Inspect IndexedDB usage.
- Monitor IndexedDB usage - Eliminate redundant operations.
- Check for unnecessary operations - Confirm transaction enforcement.
- Verify transaction usage
## Reference Materials
## Resources - [Project Demo](https://priceless-keller-d097e5.netlify.app/)
- [Project Demo](https://priceless-keller-d097e5.netlify.app/) - [Example Project](https://github.com/jlongster/absurd-example-project)
- [Example Project](https://github.com/jlongster/absurd-example-project) - [Blog Post](https://jlongster.com/future-sql-web)
- [Blog Post](https://jlongster.com/future-sql-web) - [SQL.js Documentation](https://github.com/sql-js/sql.js/)
- [SQL.js Documentation](https://github.com/sql-js/sql.js/)

280
src/views/ContactImportView.vue

@ -123,74 +123,222 @@
<script lang="ts"> <script lang="ts">
/** /**
* @file Contact Import View Component * ContactImportView - Contact Import and Batch Processing Page
* @author Matthew Raymer *
* * This component handles the batch import of contacts with comprehensive
* This component handles the import of contacts into the TimeSafari app. * validation, duplicate detection, and field comparison capabilities.
* It supports multiple import methods and handles duplicate detection, * It provides users with detailed information about each contact before
* contact validation, and visibility settings. * importing, allowing them to make informed decisions about their contact list.
* *
* Import Methods: * ## How the Contact Import Page Works
* 1. Direct URL Query Parameters: *
* Example: /contact-import?contacts=[{"did":"did:example:123","name":"Alice"}] * ### Page Entry and Data Processing
* *
* 2. JWT in URL Path: * **Entry Points**:
* Example: /contact-import/eyJhbGciOiJFUzI1NksifQ... * - **URL Parameters**: Direct navigation with contact data in URL
* - Supports both single and bulk imports * - **Contact Input Form**: Redirected from ContactsView with parsed data
* - JWT payload can be either: * - **Manual Entry**: Users can input contact data directly
* a) Array format: { contacts: [{did: "...", name: "..."}, ...] } *
* b) Single contact: { own: true, did: "...", name: "..." } * **Data Processing Pipeline**:
* * 1. **Input Validation**: Parse and validate contact data format
* 3. Manual JWT Input: * 2. **Contact Analysis**: Check each contact against existing database
* - Accepts pasted JWT strings * 3. **Duplicate Detection**: Identify existing contacts and compare fields
* - Validates format and content before processing * 4. **UI Preparation**: Prepare contact list with status indicators
* *
* URL Examples: * ### Contact Analysis and Display
*
* **Contact Status Classification**:
* - **New Contacts** (Green): Contacts not in database
* - **Existing Contacts** (Orange): Contacts already in database
* - **Identical Contacts**: Existing contacts with no field differences
*
* **Field Comparison System**:
* - **Automatic Detection**: Compare all contact fields
* - **Difference Display**: Show old vs new values in table format
* - **User Decision**: Allow users to see what will be updated
*
* **Contact List Structure**:
* ```typescript
* interface ContactImportItem {
* did: string; // Decentralized identifier
* name?: string; // Display name
* publicKey?: string; // Public key
* publicKeyBase64?: string; // Base64 encoded key
* status: 'new' | 'existing'; // Import status
* differences?: FieldDifferences; // Field comparison results
* }
* ``` * ```
* # Bulk import via query params *
* /contact-import?contacts=[ * ### User Interface Components
* {"did":"did:example:123","name":"Alice"}, *
* {"did":"did:example:456","name":"Bob"} * **Header Section**:
* ] * - **Back Navigation**: Return to previous page
* * - **Page Title**: "Contact Import" heading
* # Single contact via JWT * - **Loading State**: Spinner during data processing
* /contact-import/eyJhbGciOiJFUzI1NksifQ.eyJvd24iOnRydWUsImRpZCI6ImRpZDpleGFtcGxlOjEyMyJ9... *
* * **Visibility Settings**:
* # Bulk import via JWT * - **Activity Visibility Checkbox**: Control activity sharing with imported contacts
* /contact-import/eyJhbGciOiJFUzI1NksifQ.eyJjb250YWN0cyI6W3siZGlkIjoiZGlkOmV4YW1wbGU6MTIzIn1dfQ... * - **Global Setting**: Applies to all contacts being imported
* *
* # Redirect to contacts page (single contact) * **Contact List Display**:
* /contacts?contactJwt=eyJhbGciOiJFUzI1NksifQ... * - **Contact Cards**: Individual contact information with:
* - Selection checkbox for import control
* - Contact name and DID display
* - Status indicator (New/Existing)
* - Field comparison table for existing contacts
*
* **Field Comparison Table**:
* - **Three-Column Layout**: Field name, old value, new value
* - **Difference Highlighting**: Clear visual indication of changes
* - **Comprehensive Coverage**: All contact fields are compared
*
* **Import Controls**:
* - **Select All/None**: Bulk selection controls
* - **Individual Selection**: Per-contact import control
* - **Import Button**: Execute the selected imports
*
* ### Data Processing Logic
*
* **Contact Validation**:
* ```typescript
* // Validate DID format
* const isValidDid = (did: string): boolean => {
* return did.startsWith('did:') && did.length > 10;
* };
*
* // Check for existing contact
* const existingContact = await $getContact(did);
* const isExisting = existingContact !== null;
* ``` * ```
* *
* Features: * **Field Comparison Algorithm**:
* - Automatic duplicate detection * ```typescript
* - Field-by-field comparison for existing contacts * // Compare contact fields
* - Batch visibility settings * const compareFields = (existing: Contact, importing: Contact) => {
* - Auto-import for single new contacts * const differences: FieldDifferences = {};
* - Error handling and validation *
* * for (const field of ['name', 'publicKey', 'publicKeyBase64']) {
* State Management: * if (existing[field] !== importing[field]) {
* - Tracks existing contacts * differences[field] = {
* - Maintains selection state for bulk imports * old: existing[field] || '',
* - Records differences for duplicate contacts * new: importing[field] || ''
* - Manages visibility settings * };
* * }
* Security Considerations: * }
* - JWT validation for imported contacts *
* - Visibility control per contact * return differences;
* - Error handling for malformed data * };
* * ```
* @example *
* // Component usage in router * **Import Decision Logic**:
* { * - **New Contact**: Add to database with all provided fields
* path: "/contact-import/:jwt?", * - **Existing Contact with Differences**: Update with new field values
* name: "contact-import", * - **Existing Contact without Differences**: Skip import (already identical)
* component: ContactImportView * - **Invalid Contact**: Skip import and show error
* } *
* * ### Batch Import Process
* @see {@link Contact} for contact data structure *
* @see {@link setVisibilityUtil} for visibility management * **Pre-Import Validation**:
* - Verify all selected contacts are valid
* - Check database constraints
* - Validate visibility settings
*
* **Database Transaction**:
* ```typescript
* // Execute batch import
* const importContacts = async () => {
* const selectedContacts = contactsImporting.filter((_, index) =>
* contactsSelected[index]
* );
*
* await $beginTransaction();
*
* try {
* for (const contact of selectedContacts) {
* if (contactsExisting[contact.did]) {
* await $updateContact(contact.did, contact);
* } else {
* await $addContact(contact);
* }
* }
*
* await $commitTransaction();
* notify.success('Contacts imported successfully');
* } catch (error) {
* await $rollbackTransaction();
* notify.error('Import failed: ' + error.message);
* }
* };
* ```
*
* **Post-Import Actions**:
* - Update contact list in parent component
* - Apply visibility settings if enabled
* - Navigate back to contacts list
* - Display success/error notifications
*
* ### Error Handling and Edge Cases
*
* **Input Validation Errors**:
* - Malformed JSON data
* - Invalid DID format
* - Missing required fields
* - Empty contact arrays
*
* **Database Errors**:
* - Constraint violations
* - Storage quota exceeded
* - Concurrent access conflicts
* - Transaction failures
*
* **UI Error Recovery**:
* - Graceful handling of network failures
* - Retry mechanisms for failed operations
* - Clear error messages for users
* - Fallback options for unsupported features
*
* ### Performance Optimizations
*
* **Efficient Processing**:
* - Batch database operations
* - Optimized field comparison algorithms
* - Lazy loading of contact details
* - Debounced UI updates
*
* **Memory Management**:
* - Cleanup of temporary data structures
* - Proper disposal of event listeners
* - Efficient state management
* - Garbage collection optimization
*
* **UI Responsiveness**:
* - Asynchronous data processing
* - Progressive loading of contact data
* - Non-blocking UI updates
* - Optimized rendering for large lists
*
* ### Integration Points
*
* **Database Integration**:
* - PlatformServiceMixin for database operations
* - Transaction-based data integrity
* - Optimized queries for contact retrieval
* - Proper error handling and rollback
*
* **Navigation Integration**:
* - Route-based data passing
* - Deep linking support
* - Back navigation handling
* - Modal dialog management
*
* **Notification System**:
* - Success/error message display
* - Progress indication during import
* - User feedback for all operations
* - Accessibility-compliant notifications
*
* @author Matthew Raymer
* @date 2025-08-04
*/ */
import * as R from "ramda"; import * as R from "ramda";

138
src/views/ContactsView.vue

@ -123,6 +123,144 @@
</template> </template>
<script lang="ts"> <script lang="ts">
/**
* ContactsView - Main Contacts Management Page
*
* This component serves as the central hub for contact management in Time Safari.
* It provides a comprehensive interface for viewing, adding, importing, and managing
* contacts with various input methods and bulk operations.
*
* ## How the Contacts Page Works
*
* ### Contact Input and Import Workflow
*
* **ContactInputForm Component**:
* - **Input Field**: Accepts contact data in multiple formats:
* - Individual contact: `"did:ethr:0x..., Alice, publicKey"`
* - JSON array: `"Paste this: [{"did":"did:ethr:0x...","name":"Alice"}]"`
* - URL with contact data: `"https://example.com/contact-data"`
* - **Add Button**: Triggers contact processing and validation
* - **QR Scanner**: Alternative input method for mobile devices
* - **Real-time Validation**: Checks DID format and required fields
*
* **Contact Processing Logic**:
* 1. **Input Parsing**: The system parses the input to determine format
* 2. **Data Validation**: Validates DID format and required fields
* 3. **Duplicate Detection**: Checks if contact already exists
* 4. **Import Decision**:
* - Single contact: Direct addition to database
* - Multiple contacts: Redirect to ContactImportView for batch processing
* - Invalid data: Display error message
*
* **Import Workflow**:
* - **Single Contact**: Added directly with success notification
* - **Multiple Contacts**: Redirected to ContactImportView for:
* - Contact comparison and selection
* - Field difference display
* - Batch import execution
* - Visibility settings configuration
*
* ### Contact List Management
*
* **ContactListItem Components**:
* - **Contact Display**: Name, DID, and identicon
* - **Selection Checkboxes**: For bulk operations
* - **Action Buttons**: Gift, offer, and contact management
* - **Status Indicators**: Online/offline status, activity visibility
*
* **Bulk Operations**:
* - **Select All**: Toggle selection of all contacts
* - **Copy Selected**: Export selected contacts as JSON/CSV
* - **Bulk Actions**: Gift amounts, visibility settings
*
* **Contact Actions**:
* - **Gift Dialog**: Record gifts given to/received from contact
* - **Offer Dialog**: Create and manage offers
* - **Contact Edit**: Modify contact information
* - **Large Identicon**: View full-size contact identicon
*
* ### Data Flow and State Management
*
* **Contact Data Structure**:
* ```typescript
* interface Contact {
* did: string; // Decentralized identifier
* name?: string; // Display name (optional)
* publicKey?: string; // Public key for verification
* publicKeyBase64?: string; // Base64 encoded public key
* visibility?: boolean; // Activity visibility setting
* }
* ```
*
* **State Management**:
* - **Contact List**: Reactive list of all user contacts
* - **Selection State**: Track selected contacts for bulk operations
* - **UI State**: Toggle visibility of give totals, actions, etc.
* - **Modal State**: Manage dialog visibility and data
*
* **Database Operations**:
* - **Contact Addition**: Add new contacts with validation
* - **Contact Updates**: Modify existing contact information
* - **Contact Deletion**: Remove contacts (with confirmation)
* - **Bulk Operations**: Process multiple contacts efficiently
*
* ### Error Handling and User Feedback
*
* **Input Validation Errors**:
* - Invalid DID format
* - Missing required fields
* - Malformed JSON data
* - Network errors for URL-based imports
*
* **User Notifications**:
* - Success messages for successful operations
* - Error messages with specific details
* - Warning messages for potential issues
* - Confirmation dialogs for destructive actions
*
* **Error Recovery**:
* - Graceful handling of network failures
* - Retry mechanisms for failed operations
* - Fallback options for unsupported features
*
* ### Performance Optimizations
*
* **Contact List Rendering**:
* - Virtual scrolling for large contact lists
* - Efficient filtering and sorting
* - Lazy loading of contact details
*
* **Database Operations**:
* - Batch processing for multiple contacts
* - Transaction-based updates for data integrity
* - Optimized queries for contact retrieval
*
* **UI Responsiveness**:
* - Debounced input validation
* - Asynchronous contact processing
* - Progressive loading of contact data
*
* ### Integration Points
*
* **Platform Services**:
* - Database operations via PlatformServiceMixin
* - QR code scanning via platform-specific implementations
* - File system access for contact export
*
* **External Services**:
* - Endorser.ch for contact verification
* - JWT token processing for secure imports
* - URL-based contact data retrieval
*
* **Navigation Integration**:
* - Deep linking to contact import
* - Route-based contact filtering
* - Modal dialog management
*
* @author Matthew Raymer
* @date 2025-08-04
*/
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import { Buffer } from "buffer/"; import { Buffer } from "buffer/";
import { IndexableType } from "dexie"; import { IndexableType } from "dexie";

665
test-playwright/45-contact-import.spec.ts

File diff suppressed because it is too large
Loading…
Cancel
Save