Implement strict validation to prevent unauthorized email status changes:
- Force status to Unverified when email address changes
- Only allow client to reset status to Unverified (via reset button)
- Block client from upgrading status (Unverified→Verified, etc.)
- All status upgrades must happen server-side via verification links
This prevents attackers from:
- Submitting new emails with fake "verified" status
- Bypassing email verification by modifying client requests
- Escalating email status without proper verification flow
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add tenantEmailStatus hidden field to LocationEditForm
- Update locationActions to persist email status across all scopes
- Add reset button for unsubscribed email status
- Improve email status display with new/modified indicators
- Update translations for email status messages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
LocationCard:
- Include email status in card info section display condition
- Remove emoji suffixes (icons already convey status visually)
LocationEditForm:
- Enable autoBillFwd and rentDueNotification toggles
- Only show email status when displayed email matches saved email
- Show unverified status when email is changed or for new emails
- Remove emoji suffixes from status messages
- Add left margin to status display
Messages (EN/HR):
- More descriptive email status messages in both languages
- LocationCard: "tenant email not verified" vs "Email not verified"
- LocationEditForm: Clearer explanations like "this e-mail address
will need to be verified by the tenant"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added tenantEmail and tenantEmailStatus fields to the MongoDB projection
in fetchAllLocations() so LocationCard can display email status indicators.
Previously these fields were always undefined in LocationCard because they
weren't included in the aggregation pipeline's $project stage.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Security Enhancement:
- Server-side validation of email status before allowing verification
- Only allow verifying emails in VerificationPending state
- Show "Action not possible" message for invalid states
- Extract and validate share-id on server side
- Return 404 for invalid share-ids or missing tenant emails
Implementation:
- Convert page.tsx to async server component
- Fetch location and check tenantEmailStatus
- Pass isPending prop to client component
- Add bilingual "not-allowed" translations (same as unsubscribe page)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Make error message more generic and less specific:
- Change title from "Action Not Allowed" to "Action not possible"
- Simplify message to cover broader error cases
- Fix typo: "performe" → "performed"
- Apply same changes to Croatian version
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Security Enhancement:
- Server-side validation of email status before allowing unsubscribe
- Only allow unsubscribing from verified emails
- Show "Action Not Allowed" message for unverified/unsubscribed emails
- Extract and validate share-id on server side
- Return 404 for invalid share-ids or missing tenant emails
Implementation:
- Convert page.tsx to async server component
- Fetch location and check tenantEmailStatus
- Pass isVerified prop to client component
- Add bilingual "not-allowed" translations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Display all email statuses (Unverified, VerificationPending, Verified, Unsubscribed)
- Show appropriate icons and colors for each status
- Add bilingual translations for status labels
- Use UTF-8 emojis (⚠️⏳✅✉️) alongside Heroicons
- Position indicator before tenantEmail-error div
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Display email status when not Verified
- Show appropriate icons and colors for each status
- Add bilingual translations for status labels
- Use UTF-8 emojis (⚠️⏳✉️) alongside Heroicons
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create /email/unsubscribe/[id] route with page and component
- Add share-id validation and 404 on invalid links
- Add bilingual translations (English/Croatian)
- Implement unsubscribe UI with success/error states
- Call unsubscribeTenantEmail server action on button click
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create /email/verify/[id] route with page and component
- Add share-id validation and 404 on invalid links
- Add bilingual translations (English/Croatian)
- Implement verification UI with success/error states
- Call verifyTenantEmail server action on button click
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Export EmailStatus enum from db-types.ts
- Add verifyTenantEmail server action
- Add unsubscribeTenantEmail server action
- Both actions update current and all subsequent matching locations
- Match criteria: userId, name, tenantEmail, yearMonth >= current
- Share-id validation using existing shareChecksum utilities
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add EmailStatus enum and tracking fields to BillingLocation to support
email delivery monitoring (bounces, complaints, unsubscribes).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Update launch.json and tasks.json to use multi-root workspace folder syntax for correct path resolution.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Moved Dockerfile, build.sh, and .dockerignore to web-app/ for better
project encapsulation. Each project now contains its own build configuration.
## Changes
- Moved Dockerfile to web-app/ and simplified paths
- Moved build.sh to web-app/
- Moved .dockerignore to web-app/
- Updated Dockerfile to work from web-app/ context (no workspace references)
- Updated documentation for new build workflow
## Build Workflow
- Build: Run from web-app/ directory (`cd web-app && ./build.sh 2.20.0`)
- Deploy: Run from repository root (`./deploy-standalone.sh 2.20.0`)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Restructured the repository into a monorepo to better organize application code
and maintenance scripts.
## Workspace Structure
- web-app: Next.js application (all app code moved from root)
- housekeeping: Database backup and maintenance scripts
## Key Changes
- Moved all application code to web-app/ using git mv
- Moved database scripts to housekeeping/ workspace
- Updated Dockerfile for monorepo build process
- Updated docker-compose files (volume paths: ./web-app/etc/hosts/)
- Updated .gitignore for workspace-level node_modules
- Updated documentation (README.md, CLAUDE.md, CHANGELOG.md)
## Migration Impact
- Root package.json now manages workspaces
- Build commands delegate to web-app workspace
- All file history preserved via git mv
- Docker build process updated for workspace structure
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>