322 lines
14 KiB
Markdown
Executable File
322 lines
14 KiB
Markdown
Executable File
# CyberHybridHub - Website Goals and Services
|
|
|
|
## Overview
|
|
|
|
CyberHybridHub is a comprehensive web platform designed to serve two primary
|
|
purposes: providing free financial calendar services and offering a dedicated
|
|
portal for rental property management.
|
|
|
|
This repo implements the rental property portal as a Fresh (Deno) web app with
|
|
landlord and tenant flows, a lightweight in-memory E2E test mode, and a
|
|
Playwright test suite designed to be deterministic and repeatable.
|
|
|
|
## Primary Services
|
|
|
|
### 1. Free Financial Calendar Services
|
|
|
|
Our platform offers complimentary financial calendar tools designed to help
|
|
users:
|
|
|
|
- Track important financial dates and deadlines
|
|
- Monitor payment schedules and due dates
|
|
- Plan for financial events and obligations
|
|
- Stay organized with customizable calendar views
|
|
- Receive notifications for upcoming financial milestones
|
|
|
|
These services are provided at no cost to ensure financial planning tools are
|
|
accessible to everyone.
|
|
|
|
### 2. Rental Management Portal
|
|
|
|
CyberHybridHub serves as a centralized hub for rental property management,
|
|
connecting:
|
|
|
|
#### For Renters:
|
|
|
|
- **Payment Management**: Secure online rent payments and transaction history
|
|
- **Service Requests**: Submit and track maintenance requests
|
|
- **Communication**: Direct messaging with landlords and property managers
|
|
- **Document Management**: Access lease agreements, receipts, and important
|
|
documents
|
|
- **Payment Reminders**: Automated notifications for upcoming rent payments
|
|
|
|
#### For Landlords:
|
|
|
|
- **Rent Collection**: Streamlined payment processing and tracking
|
|
- **Property Management**: Organize multiple properties and units
|
|
- **Tenant Communication**: Centralized messaging and announcements
|
|
- **Maintenance Coordination**: Efficient service request management
|
|
- **Financial Reporting**: Revenue tracking and expense management
|
|
- **Document Storage**: Secure storage for leases, inspections, and records
|
|
|
|
## Key Features
|
|
|
|
### Security & Privacy
|
|
|
|
- Encrypted data transmission and storage
|
|
- Secure payment processing
|
|
- User authentication and access controls
|
|
- Privacy-focused design
|
|
|
|
### User Experience
|
|
|
|
- Intuitive dashboard for both renters and landlords
|
|
- Mobile-responsive design
|
|
- Real-time notifications and updates
|
|
- Easy navigation and clean interface
|
|
|
|
### Integration
|
|
|
|
- Calendar synchronization with personal devices
|
|
- Payment gateway integration
|
|
- Email and SMS notifications
|
|
- Document upload and management system
|
|
|
|
## Mission Statement
|
|
|
|
CyberHybridHub aims to simplify financial planning and rental management by
|
|
providing free, accessible tools that empower users to take control of their
|
|
financial obligations while fostering better communication and efficiency in the
|
|
rental market.
|
|
|
|
## Target Audience
|
|
|
|
- Individual renters seeking better payment and service management
|
|
- Landlords and property managers looking for streamlined operations
|
|
- Anyone interested in free financial planning and calendar tools
|
|
- Property management companies seeking efficient digital solutions
|
|
|
|
## Technology Stack
|
|
|
|
Built with modern web technologies to ensure reliability, security, and
|
|
scalability:
|
|
|
|
- Frontend: Responsive web interface
|
|
- Backend: Secure API and database management
|
|
- Payment Processing: Industry-standard payment gateways
|
|
- Security: End-to-end encryption and best practices
|
|
|
|
## App Architecture Summary (Rental Portal)
|
|
|
|
- **Core flows**: onboarding (landlord + tenant), dashboards, properties,
|
|
leases, maintenance, messages, payments, documents, reminders,
|
|
portfolio/multi-property.
|
|
- **Routing**: UI pages live under `routes/` (e.g., `routes/landlord/*`,
|
|
`routes/tenant/*`, `routes/onboarding/*`), API endpoints under `routes/api/*`.
|
|
- **Services**: business logic in `services/*`. When `E2E_TEST=true`, services
|
|
read/write deterministic fixtures from `services/e2eFixtures.ts` instead of
|
|
the database.
|
|
- **Auth in tests**: E2E mode accepts a header `x-e2e-user` to bypass auth
|
|
(`services/stateMiddleware.ts`), and UI tests set a skip-encryption flag via
|
|
`tests/e2e/helpers.ts`.
|
|
|
|
## Deterministic E2E Testing (Playwright)
|
|
|
|
The goal is to always verify functional behavior without flakiness or state
|
|
drift.
|
|
|
|
### How E2E Mode Works
|
|
|
|
- **E2E env**: `E2E_TEST=true` enables fixture-backed services
|
|
(`services/e2eFixtures.ts`).
|
|
- **Auth bypass**: use `x-e2e-user` header (values like `landlord`, `tenant`,
|
|
`landlord-onboarding`) to map to fixture users.
|
|
- **Deterministic time**: `applyDeterministicPage()` stubs `Date.now()` and
|
|
`Math.random()` and disables animations.
|
|
- **Encryption bypass**: `useE2EUser()` sets `window.__E2E_SKIP_ENCRYPTION__`
|
|
and a localStorage flag to keep test data readable.
|
|
- **Web server**: Playwright config uses `deno task dev` with `E2E_TEST=true`
|
|
and a fixed base URL.
|
|
|
|
### Writing / Updating `tests/e2e/*`
|
|
|
|
- Prefer **resilient assertions** (e.g., check for a section header or a
|
|
state-dependent branch) because E2E data can be mutated across tests.
|
|
- When adding UI flows, make sure the corresponding service uses E2E fixtures
|
|
(or add fixture support in `services/e2eFixtures.ts`).
|
|
- Use `applyDeterministicPage()` and `useE2EUser()` at the start of each UI
|
|
test.
|
|
- Use `e2eHeaders()` for API-level tests to route through the E2E user context.
|
|
- If a flow writes data (create/update), the fixture state persists for the rest
|
|
of the run. Avoid assuming pristine state unless you add explicit resets.
|
|
|
|
### Available Test Methodologies (Deterministic Playwright)
|
|
|
|
- **UI E2E (browser)**: `page.goto(...)` + user interactions + assertions on UI
|
|
outcomes.
|
|
- **API E2E**: `request.get/post(...)` with `e2eHeaders(...)` for deterministic
|
|
API coverage without UI.
|
|
- **Hybrid E2E**: create data via API, validate via UI (or vice versa) for
|
|
full-stack coverage.
|
|
|
|
### Running Tests
|
|
|
|
- `deno task e2e` (uses Playwright + deterministic server config from
|
|
`playwright.config.ts`).
|
|
|
|
## Future Development
|
|
|
|
Planned enhancements include:
|
|
|
|
- Advanced financial analytics and reporting
|
|
- Mobile applications for iOS and Android
|
|
- Integration with accounting software
|
|
- Expanded property management features
|
|
- AI-powered financial insights and recommendations
|
|
|
|
# Fresh project
|
|
|
|
Your new Fresh project is ready to go. You can follow the Fresh "Getting
|
|
Started" guide here: https://fresh.deno.dev/docs/getting-started
|
|
|
|
### Usage
|
|
|
|
Make sure to install Deno:
|
|
https://docs.deno.com/runtime/getting_started/installation
|
|
|
|
Then start the project in development mode:
|
|
|
|
```
|
|
deno task dev
|
|
```
|
|
|
|
deno run -A -r jsr:@fresh/update
|
|
|
|
deno compile -A --target x86_64-unknown-linux-gnu --include ./_fresh/client
|
|
--output ../server ./compiled-entry.js deno compile -A --target
|
|
x86_64-pc-windows-msvc --include ./_fresh/client --output ../server.exe
|
|
./_fresh/compiled-entry.js
|
|
|
|
deno compile -A --target x86_64-apple-darwin --include ./_fresh/client --output
|
|
./server ./_fresh/compiled-entry.js
|
|
|
|
docker login cyberhybridhubreg.azurecr.io docker pull
|
|
cyberhybridhubreg.azurecr.io/cyberhybridhub:latest docker run -it -p 8080:8080
|
|
cyberhybridhubreg.azurecr.io/cyberhybridhub:latest tail -f /dev/null
|
|
|
|
az acr import --name cyberhybridhub --source denoland/deno:latest --image
|
|
denoland/deno:latest CMD ["tail", "-f", "/bin/bash] ENTRYPOINT ["dotnet",
|
|
"DotNet.Docker.dll"]
|
|
|
|
docker build -t app . && docker run -it -p 8080:8080 app
|
|
|
|
docker commit confident_lederberg cyberhybridhub/deno2.5.4-dotnet8.0.414:latest
|
|
docker login cyberhybridhub.azurecr.io docker tag
|
|
cyberhybridhub/deno2.5.4-dotnet8.0.414:latest
|
|
cyberhybridhub.azurecr.io/deno2.5.4-dotnet8.0.414:latest docker push
|
|
cyberhybridhub.azurecr.io/deno2.5.4-dotnet8.0.414:latest
|
|
|
|
docker build -t app3 . && docker run -it -p 8080:8080 app3 sh
|
|
|
|
apt-get update RUN if ! command -v git; then\
|
|
apt-get update && apt-get install -y git;\
|
|
fi && git --version
|
|
|
|
docker run -d -p 8080:80 --name myapp --entrypoint "dotnet"
|
|
cyberhybridhub.azurecr.io/dotnet/aspnet:8.0-alpine <your-app>.dll
|
|
|
|
apt-get update apt-get install -y wget apt-transport-https wget
|
|
https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb -O
|
|
packages-microsoft-prod.deb dpkg -i packages-microsoft-prod.deb rm
|
|
packages-microsoft-prod.deb
|
|
|
|
mkdir -p /tmp/deno-compile-server && ln -sfn "$(pwd)/server"
|
|
/tmp/deno-compile-server/server && dotnet AzureFront.CyberHybridHub.dll
|
|
|
|
2025-10-16T13:19:46.1385179Z NotFound: path not found: stat
|
|
'/tmp/deno-compile-server/_fresh/client\assets\client-entry-DNH4ZUpx.css'
|
|
2025-10-16T13:19:46.1385699Z at Object.stat (ext:deno_fs/30_fs.js:425:21)
|
|
2025-10-16T13:19:46.1385787Z at ProdBuildCache.readFile
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:5279:50)
|
|
2025-10-16T13:19:46.1385814Z at freshServeStaticFiles
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:5835:35)
|
|
2025-10-16T13:19:46.1385839Z at Context.fn
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4403:34)
|
|
2025-10-16T13:19:46.1385862Z at segmentMiddleware
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4588:26)
|
|
2025-10-16T13:19:46.1385885Z at fn
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4403:34)
|
|
2025-10-16T13:19:46.1385908Z at
|
|
file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4419:20
|
|
2025-10-16T13:19:46.1385934Z at NoopContextManager.with
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:981:15)
|
|
2025-10-16T13:19:46.1385957Z at ContextAPI.with
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:1048:42)
|
|
2025-10-16T13:19:46.1385981Z at NoopTracer.startActiveSpan
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:1328:27) {
|
|
2025-10-16T13:19:46.1386002Z name: "NotFound", 2025-10-16T13:19:46.1386056Z
|
|
code: "ENOENT" 2025-10-16T13:19:46.1386076Z } 2025-10-16T13:19:46.8441754Z
|
|
NotFound: path not found: stat
|
|
'/tmp/deno-compile-server/_fresh/client\assets\client-entry-9ekbL4RI.js'
|
|
2025-10-16T13:19:46.8442151Z at Object.stat (ext:deno_fs/30_fs.js:425:21)
|
|
2025-10-16T13:19:46.8442187Z at ProdBuildCache.readFile
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:5279:50)
|
|
2025-10-16T13:19:46.8442212Z at freshServeStaticFiles
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:5835:35)
|
|
2025-10-16T13:19:46.8442242Z at Context.fn
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4403:34)
|
|
2025-10-16T13:19:46.8442269Z at segmentMiddleware
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4588:26)
|
|
2025-10-16T13:19:46.8442291Z at fn
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4403:34)
|
|
2025-10-16T13:19:46.8442364Z at
|
|
file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4419:20
|
|
2025-10-16T13:19:46.844239Z at NoopContextManager.with
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:981:15)
|
|
2025-10-16T13:19:46.8442414Z at ContextAPI.with
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:1048:42)
|
|
2025-10-16T13:19:46.8442438Z at NoopTracer.startActiveSpan
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:1328:27) {
|
|
2025-10-16T13:19:46.8442458Z name: "NotFound", 2025-10-16T13:19:46.8442477Z
|
|
code: "ENOENT" 2025-10-16T13:19:46.8442497Z } 2025-10-16T13:19:49.120541Z
|
|
NotFound: path not found: stat
|
|
'/tmp/deno-compile-server/_fresh/client\favicon.ico'
|
|
2025-10-16T13:19:49.1205856Z at Object.stat (ext:deno_fs/30_fs.js:425:21)
|
|
2025-10-16T13:19:49.1205895Z at ProdBuildCache.readFile
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:5279:50)
|
|
2025-10-16T13:19:49.1205918Z at freshServeStaticFiles
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:5835:35)
|
|
2025-10-16T13:19:49.1205942Z at Context.fn
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4403:34)
|
|
2025-10-16T13:19:49.1205965Z at segmentMiddleware
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4588:26)
|
|
2025-10-16T13:19:49.1205988Z at fn
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4403:34)
|
|
2025-10-16T13:19:49.120601Z at
|
|
file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:4419:20
|
|
2025-10-16T13:19:49.1206647Z at NoopContextManager.with
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:981:15)
|
|
2025-10-16T13:19:49.1206683Z at ContextAPI.with
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:1048:42)
|
|
2025-10-16T13:19:49.120674Z at NoopTracer.startActiveSpan
|
|
(file:///tmp/deno-compile-server/_fresh/server/server-entry.mjs:1328:27) {
|
|
2025-10-16T13:19:49.120676Z name: "NotFound", 2025-10-16T13:19:49.1206778Z code:
|
|
"ENOENT" 2025-10-16T13:19:49.1206796Z }
|
|
|
|
// {
|
|
// "id": "MXhUaBIBQkePiTHfY-3y3hrn5C7OZ1RAjFmyNHAKbQA",
|
|
// "deletedDateTime": null,
|
|
// "appRoleId": "d4ce6e5d-4a93-43ae-b2f4-230e76248917",
|
|
// "createdDateTime": "2025-10-20T19:17:23.9036855Z",
|
|
// "principalDisplayName": "Nathan Live Anderson",
|
|
// "principalId": "68547831-0112-4742-8f89-31df63edf2de",
|
|
// "principalType": "User",
|
|
// "resourceDisplayName": "cyberhybridhub",
|
|
// "resourceId": "c7f12958-4ee8-4a07-acb8-bf4ac2dcac2b"
|
|
// }
|
|
Request headers: {
|
|
|
|
accept:
|
|
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,_/_;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
|
"accept-encoding": "gzip, deflate, br, zstd", "accept-language":
|
|
"en-US,en;q=0.9", "cache-control": "max-age=0", connection: "keep-alive",
|
|
cookie: "xx-state-id=353bd790-b53e-4a67-89a1-cad4886c9e57", host:
|
|
"127.0.0.1:8080", referer: "http://127.0.0.1:8080/", "sec-ch-ua": '"Microsoft
|
|
Edge";v="141", "Not?A_Brand";v="8", "Chromium";v="141"', "sec-ch-ua-mobile":
|
|
"?0", "sec-ch-ua-platform": '"Linux"', "sec-fetch-dest": "document",
|
|
"sec-fetch-mode": "navigate", "sec-fetch-site": "same-origin",
|
|
"upgrade-insecure-requests": "1", "user-agent": "Mozilla/5.0 (X11; Linux x86_64)
|
|
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36
|
|
Edg/141.0.0.0" } Request cookies: { "xx-state-id":
|
|
"353bd790-b53e-4a67-89a1-cad4886c9e57" }
|