- Added DB integration details for external email system - Clarified share-id validation (404 on invalid) - Enhanced subsequent matching to include tenantEmail - Specified exact UI placement for email status indicators - Fixed typo: EmailStatus.Verifies → EmailStatus.Verified 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
5.9 KiB
Context
App users (landlord) can assign tenantEmail to a BillingLocation.
This is a e-mail address will be used to notify the tenant when the rent is due and/or the utility bills are due.
E-mail verification
To prevent missuse and ensure that the e-mail is correct, before an e-mail address can be used by the automatic notification system, the tenant needs to verifies that he/she accepts to receive notifications.
This verification is done via a link sent to the tenant in a verification-request e-mail, which is sent to the tenant automatically when the landloard (app user) assigns this e-mail address to a BillingLocation.
Sending of this verification-request e-mail is handled by a system separate from NextJS app in web-app workspace. It detects newly assigned addresses from their status bein equal EmailStatus.Unverified. The two systems don't talk to each other at all - what's holding them together is the DB.
Implementation details
Verification link points to the NextJS app in web-app workspace at path /email/verify/[share-id] (share-id is calculated using generateShareId from /home/kneecola/projects/evidencija-rezija/web-app/app/lib/shareChecksum.ts).
The web page served at this path cerifies if the [share-id] is correct and if not it shows 404 page.
The web page served at this path contains an text explanation and "Verify e-mail" button.
The text includes the following information:
- what the web app is about - very short into
- why the e-mail was sent = because the landloard of the property
BillingLocation.nameconfigured the rent (BillingLocation.rentDueNotification) and/or utility bills (BillingLocation.billFwdStrategy) to be delivered to that e-mail address - what will hapen if he/she clicks on the "Verify e-mail" button = they will be receiving rent due (
BillingLocation.rentDueNotification) or utility bills due (BillingLocation.billFwdStrategy) notification or both - 2x a month - depending on the config set by the landloard - opt-out infomation (they can ignore this e-mail, but can also opt-out at any moment)
If the user clicks the button "Verify e-mail" this triggers update of BillingLocation.tenantEmailStatus.
Here's the expected stats flow:
- landloard/app user assigns an an new address to
BillingLocation->BillingLocation.tenantEmailStatusis set toEmailStatus.Unverified - an automated system detects that a new address was set (as indicated by
EmailStatus.Unverifiedstatus), it then sets verification-email ->BillingLocation.tenantEmailStatusis set toEmailStatus.VerificationPending - tenant click the link from the verification-requets e-mail ->
BillingLocation.tenantEmailStatusis set toEmailStatus.Verified
Note: status is updated for the BillingLocation inidcated by locationID (decoded from [share-id] param), and all subsequent (later in time) matching BillingLocation records (matched by comparing BillingLocation.name, BillingLocation.userId and BillingLocation.tenantEmail). Similar pattern is already implemented in updateOrAddLocation fn in locationAction.ts (updateScope === "subsequent").
E-mail unsubscribe
Tenant can out-out from receiving e-mail notifications at any time via an unsubscribe link included at the end of every mail sent to the tenant.
Implementation details
Verification link points to the NextJS app in web-app workspace at path /email/unsubscribe/[share-id] (share-id is calculated using generateShareId from /home/kneecola/projects/evidencija-rezija/web-app/app/lib/shareChecksum.ts ... search of examples of how this function is used).
The web page served at this path contains an text explanation and "Confirm unsubscribe" button.
The text includes the following information:
- what the web app is about - very short into
- why are they receiveing e-mails from this page = because their landlord for property
BillingLocation.namehas configured the app to deliver rent due or utility bills due notification or both to that address - what will hapen if they click on "Confirm unsubscribe" = they will no longer receive rent due / utility bull due reminders
E-mail address's verification status is tracked via BillingLocation.tenantEmailStatus, which is set to EmailStatus.Unsubscribed.
Note: status is updated for the BillingLocation inidcated by locationID (decoded from [share-id] param), and all subsequent (later in time) matching BillingLocation records (matched by comparing BillingLocation.name, BillingLocation.userId and BillingLocation.tenantEmail). Similar pattern is already implemented in updateOrAddLocation fn in locationAction.ts (updateScope === "subsequent").
E-mail status in LocationCard.tsx
If the e-mail is not in EmailStatus.Verified state for a given location, then this will be indicated in LocationCard.tsx as a sibling of total-payed-label block (<div className="flex ml-1">)
E-mail status in LocationEditForm.tsx
Current e-mail status will be indicated as a sibling of:
{/* Email status indicator should go here */}
<div id="tenantEmail-error" aria-live="polite" aria-atomic="true">
...
Use appropriate utf-8 icon for each status.
Logical Units of work
Work will be split in logical units of work:
- implement e-mail verification DB logic
- implement e-mail verification page
- create text both in croatian (hr.json) and english (en.json)
- implement share-id verification (see /home/kneecola/projects/evidencija-rezija/web-app/app/[locale]/share/proof-of-payment/per-bill/[id]/route.tsx)
- implement e-mail unsubscribe DB logic
- implement e-mail unsubscribe page
- create text both in croatian (hr.json) and english (en.json)
- implement share-id verification (see /home/kneecola/projects/evidencija-rezija/web-app/app/[locale]/share/proof-of-payment/per-bill/[id]/route.tsx)
- add email status to
LocationCard.tsx - add email status to
LocationEditForm.tsx
Each logical unit of work will be commited separatley.