diff --git a/AGENTS.md b/AGENTS.md index 9e4dfa0..ba97fc2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,13 +1,17 @@ # CyberHybridHub - Deno Fresh Web App Setup Guide ## Overview -CyberHybridHub is a modern web application built with Deno Fresh framework, utilizing Drizzle ORM for database management, TailwindCSS for styling, and designed for Datona sandbox environments. + +CyberHybridHub is a modern web application built with Deno Fresh framework, +utilizing Drizzle ORM for database management, TailwindCSS for styling, and +designed for Datona sandbox environments. **Package Manager**: Use Deno CLI exclusively (no npm/yarn required) **Core Dependencies**: + - **Deno**: Latest runtime (https://deno.land/) - **Fresh Framework**: `jsr:@fresh/core@^2.2.0` - **Database**: Deno KV (built-in key-value storage) @@ -16,18 +20,20 @@ CyberHybridHub is a modern web application built with Deno Fresh framework, util - **Authentication**: Local authentication system **Database Setup**: + - Deno KV is used for Datona sandbox compatibility - Database initialized automatically on startup - No external database server required - Built-in Deno KV storage handles all data persistence **External Services**: + - **Local File Storage**: Used for blob storage in sandbox - **In-Memory Cache**: Built-in Deno KV for caching - No external service dependencies required for sandbox -**Environment Variables**: -Set the following environment variables before running the application: +**Environment Variables**: Set the following environment variables before +running the application: ```bash # Server Configuration @@ -46,6 +52,7 @@ LOCAL_DEV_MODE="true" ``` **Startup Sequence**: + 1. Install Deno: ```bash curl -LO https://github.com/denoland/deno/releases/latest/download/deno-x86_64-unknown-linux-gnu.zip @@ -58,6 +65,7 @@ LOCAL_DEV_MODE="true" 4. Start development server: `deno task dev` (Deno KV initializes automatically) **Available Deno Tasks**: + - `deno task dev` - Start development server with Vite - `deno task build` - Build for production - `deno task start` - Start production server @@ -65,12 +73,14 @@ LOCAL_DEV_MODE="true" - `deno task e2e` - Run Playwright end-to-end tests **Development Workflow**: + 1. Make code changes 2. Run `deno task check` to validate code quality 3. Test with `deno task test` and `deno task e2e` 4. Deno KV handles data persistence automatically **Datona Sandbox Deployment**: + 1. Set `SANDBOX_MODE="true"` in environment 2. Ensure all external API calls are disabled 3. Use local file storage instead of cloud services @@ -82,6 +92,7 @@ LOCAL_DEV_MODE="true" ## Architecture Overview ### Directory Structure + - `routes/` - Fresh framework route handlers and pages - `islands/` - Interactive Preact components - `components/` - Reusable UI components @@ -93,6 +104,7 @@ LOCAL_DEV_MODE="true" - `drizzle/` - Database migration files ### Key Technologies + - **Fresh**: Full-stack web framework with edge-first architecture - **Deno KV**: Built-in key-value storage for data persistence - **TailwindCSS**: Utility-first CSS framework @@ -100,6 +112,7 @@ LOCAL_DEV_MODE="true" - **Local Authentication**: JWT-based authentication system ### Authentication Flow + 1. User registers or logs in via local authentication 2. Credentials validated against Deno KV storage 3. JWT token generated for session management @@ -109,6 +122,7 @@ LOCAL_DEV_MODE="true" ## Development Guidelines ### Code Style + - Use TypeScript for all new code - Follow Fresh framework conventions - Utilize TailwindCSS for styling @@ -116,6 +130,7 @@ LOCAL_DEV_MODE="true" - Write tests for new features and functions ### Database Operations + - All data operations use Deno KV key-value storage - No schema migrations required - Automatic data persistence and backup @@ -123,10 +138,10 @@ LOCAL_DEV_MODE="true" - Simple API for CRUD operations ### Security Considerations + - Never commit secrets or API keys - Use environment variables for sensitive configuration - Implement proper input validation and sanitization - Follow OWASP security guidelines - Use local authentication to avoid external dependencies - Regular security audits and dependency updates - diff --git a/TODO.md b/TODO.md index 29f3c48..4909fbe 100644 --- a/TODO.md +++ b/TODO.md @@ -3,39 +3,50 @@ ## Code Formatting Issues (deno task check) ### Critical Issues + - **5 files not formatted properly** - Need to run `deno fmt` to fix formatting - Files affected: - `routes/tenant/messages/index.tsx` - Import order and formatting issues - - `routes/tenant/settings/index.tsx` - Function definition formatting and indentation + - `routes/tenant/settings/index.tsx` - Function definition formatting and + indentation - `services/messageService.ts` - Import order issues - Additional files with formatting problems (truncated output) ### Specific Formatting Problems + 1. **Import Statement Order** - Multiple files have incorrect import ordering -2. **Function Definition Formatting** - Functions not properly formatted according to Deno standards +2. **Function Definition Formatting** - Functions not properly formatted + according to Deno standards 3. **Indentation Issues** - Inconsistent indentation in JSX components 4. **Line Break Issues** - Missing or extra line breaks in various files ## E2E Test Failures (deno task e2e) ### Failed Tests + 1. **reminders.spec.ts:4** - "landlord can send reminder and tenant receives it" - - **Error**: Element with role "heading" and name matching /messages/i not found + - **Error**: Element with role "heading" and name matching /messages/i not + found - **Expected**: Messages heading should be visible - **Status**: Timeout after 5000ms -2. **tenant-dashboard.spec.ts:50** - "tenant messages list shows landlord communication" - - **Error**: Element with role "heading" and name matching /messages/i not found +2. **tenant-dashboard.spec.ts:50** - "tenant messages list shows landlord + communication" + - **Error**: Element with role "heading" and name matching /messages/i not + found - **Expected**: Messages heading should be visible - **Status**: Timeout after 5000ms ### Test Infrastructure Issues -- **Static File Serving Error**: Server crashes when trying to serve static files + +- **Static File Serving Error**: Server crashes when trying to serve static + files - Error: "Failed to read directory: No such file or directory (os error 2)" - Path: `/Users/nanderson/nathanAndrinoid/cyberhybridhub.com/static` - Impact: Tests failing due to missing static assets ### Root Cause Analysis + - Both failed tests are looking for a "Messages" heading that doesn't exist - This suggests either: - The messages page/component is not rendering properly @@ -45,20 +56,25 @@ ## Priority Actions ### High Priority -1. **Fix static file serving** - Create missing `/static` directory or fix configuration + +1. **Fix static file serving** - Create missing `/static` directory or fix + configuration 2. **Investigate messages page** - Check why messages heading is not rendering 3. **Run code formatting** - Execute `deno fmt` to fix all formatting issues ### Medium Priority + 1. **Review test expectations** - Verify if test assertions match actual UI 2. **Check navigation flow** - Ensure users can properly navigate to messages 3. **Fix import statements** - Correct import order in affected files ### Low Priority + 1. **Code style consistency** - Ensure all files follow consistent formatting 2. **Add error handling** - Improve error handling for missing static files ## Next Steps + 1. Create `/static` directory if missing 2. Run `deno fmt` to fix formatting 3. Debug messages page rendering issue diff --git a/routes/tenant/messages/index.tsx b/routes/tenant/messages/index.tsx index 00beba3..01f147f 100644 --- a/routes/tenant/messages/index.tsx +++ b/routes/tenant/messages/index.tsx @@ -3,10 +3,10 @@ import { define } from "../../../utils.ts"; import { page } from "fresh"; import { SessionCookie } from "../../auth/callback.ts"; import { + DashboardMessage, deleteMessagesForUser, getMessagesForUser, markMessagesAsRead, - DashboardMessage, MessagePage, } from "../../../services/messageService.ts"; import LandlordMessageSelection from "../../../islands/LandlordMessageSelection.tsx"; diff --git a/routes/tenant/property/index.tsx b/routes/tenant/property/index.tsx index 26c0044..ea33556 100644 --- a/routes/tenant/property/index.tsx +++ b/routes/tenant/property/index.tsx @@ -49,7 +49,9 @@ export const handler = define.handlers({ return page({ lease: currentLease, property, - propertyPhotos: propertyPhotos.filter((m: PropertyMedia) => m.media_type === "photo"), + propertyPhotos: propertyPhotos.filter((m: PropertyMedia) => + m.media_type === "photo" + ), leaseDocuments, }); } catch (error) { @@ -148,159 +150,167 @@ function DocumentList({ documents }: { documents: LeaseDocument[] }) { ); } -export default define.page(function TenantPropertyPage({ data }: { data: PropertyPageData }) { - const { lease, property, propertyPhotos, leaseDocuments, error } = - data as PropertyPageData; +export default define.page( + function TenantPropertyPage({ data }: { data: PropertyPageData }) { + const { lease, property, propertyPhotos, leaseDocuments, error } = + data as PropertyPageData; - if (error) { - return ( -
- {error} - -
- ); - } - - if (!property) { - return ( -
- - Property details could not be loaded. - -
- ); - } - - const addressLine = formatPropertyAddress(property); - const amenities = parseList(property.amenities); - const rules = parseList(lease?.late_fee_rules ?? ""); - const photoItems = (propertyPhotos ?? []).filter( - (photo): photo is PropertyMedia & { file_url: string } => - Boolean(photo.file_url), - ); - - return ( -
- {/* Header */} -
-
-
-

- Your Current Residence -

-

- {addressLine || "Address not available"} -

+ if (error) { + return ( +
+ {error} +
-
+ ); + } - {/* Main Content */} -
- {/* Property Photos */} - {photoItems.length > 0 && ( -
-

- Property Photos -

-
- {photoItems.map((photo) => ( - {photo.file_name - ))} + if (!property) { + return ( +
+ + Property details could not be loaded. + +
+ ); + } + + const addressLine = formatPropertyAddress(property); + const amenities = parseList(property.amenities); + const rules = parseList(lease?.late_fee_rules ?? ""); + const photoItems = (propertyPhotos ?? []).filter( + (photo): photo is PropertyMedia & { file_url: string } => + Boolean(photo.file_url), + ); + + return ( +
+ {/* Header */} +
+
+
+

+ Your Current Residence +

+

+ {addressLine || "Address not available"} +

- )} - - {/* Property Details */} -
-
-

- Property Details -

-
-
-
- - - - - - -
-
- {/* Amenities */} -
-
-

- Amenities -

-
-
- {amenities.length > 0 - ? ( -
    - {amenities.map((amenity: string) =>
  • {amenity}
  • )} -
- ) - :

No amenities listed.

} -
-
+ {/* Main Content */} +
+ {/* Property Photos */} + {photoItems.length > 0 && ( +
+

+ Property Photos +

+
+ {photoItems.map((photo) => ( + {photo.file_name + ))} +
+
+ )} - {/* Rules */} -
-
-

- Community Rules -

+ {/* Property Details */} +
+
+

+ Property Details +

+
+
+
+ + + + + + +
+
-
- {rules.length > 0 - ? ( -
    - {rules.map((rule: string) =>
  • {rule}
  • )} -
- ) - :

No specific rules listed.

} -
-
- {/* Lease Documents */} -
-
-

- Lease Documents -

-

- Your current lease agreement and related documents. -

+ {/* Amenities */} +
+
+

+ Amenities +

+
+
+ {amenities.length > 0 + ? ( +
    + {amenities.map((amenity: string) => ( +
  • {amenity}
  • + ))} +
+ ) + :

No amenities listed.

} +
-
- + + {/* Rules */} +
+
+

+ Community Rules +

+
+
+ {rules.length > 0 + ? ( +
    + {rules.map((rule: string) =>
  • {rule}
  • )} +
+ ) + : ( +

+ No specific rules listed. +

+ )} +
+
+ + {/* Lease Documents */} +
+
+

+ Lease Documents +

+

+ Your current lease agreement and related documents. +

+
+
+ +
-
- ); -}); + ); + }, +); diff --git a/routes/tenant/settings/index.tsx b/routes/tenant/settings/index.tsx index 0402a4d..4d9464e 100644 --- a/routes/tenant/settings/index.tsx +++ b/routes/tenant/settings/index.tsx @@ -56,46 +56,48 @@ export const handler = define.handlers({ }, }); -export default define.page(function TenantSettingsPage({ data }: { data: SettingsPageData }) { - const { user, error } = data as SettingsPageData; +export default define.page( + function TenantSettingsPage({ data }: { data: SettingsPageData }) { + const { user, error } = data as SettingsPageData; - if (error) { - return ( -
-
-

Error

-

{error}

-
- - Go to Dashboard - + if (error) { + return ( +
+
+

Error

+

{error}

+
+ ); + } + + return ( +
+ {/* Header */} +
+
+
+

Tenant Settings

+

+ Manage your notification and payment preferences. +

+
+
+
+ + {/* Main Content */} +
+ +
); - } - - return ( -
- {/* Header */} -
-
-
-

Tenant Settings

-

- Manage your notification and payment preferences. -

-
-
-
- - {/* Main Content */} -
- -
-
- ); -}); + }, +); diff --git a/services/messageService.ts b/services/messageService.ts index f8158bd..d64b183 100644 --- a/services/messageService.ts +++ b/services/messageService.ts @@ -9,11 +9,11 @@ import { addE2EMessage, deleteE2EMessage, deleteE2EMessagesForUser, - getE2EMessageById, - getE2EMessageThread, getE2ELeaseById, + getE2EMessageById, getE2EMessagesByLease, getE2EMessagesByUser, + getE2EMessageThread, getE2EPropertyById, getE2EUserById, isE2EEnabled,