This commit is contained in:
Nathan Anderson 2026-01-28 14:49:35 -06:00
parent cdc6e49414
commit f7f6d6a23a
5 changed files with 2757 additions and 1 deletions

99
TODO.md
View File

@ -0,0 +1,99 @@
# Lease Approval Implementation Plan
## Overview
Implement landlord approval mechanism for tenant invitation workflow. Currently, tenants can click "Start Lease" without landlord oversight. This plan adds proper approval workflow.
## Implementation Tasks
### 1. Database Schema Changes (HIGH PRIORITY)
- [ ] Add approval workflow fields to `leases` table:
- `approval_status` TEXT DEFAULT 'pending_approval'
- `approval_requested_at` BIGINT
- `approved_at` BIGINT
- `approved_by` TEXT REFERENCES users(id)
- `rejection_reason` TEXT
- [ ] Create migration SQL file
- [ ] Update database interfaces
### 2. API Endpoints (HIGH PRIORITY)
- [ ] Create `POST /api/lease/request-approval` - Tenant initiates lease
- [ ] Create `POST /api/lease/approve` - Landlord approval
- [ ] Create `POST /api/lease/reject` - Landlord rejection
- [ ] Create `GET /api/lease/pending-approvals` - Landlord dashboard
- [ ] Extend `leaseService.ts` with approval functions:
- `requestLeaseApproval()`
- `approveLease()`
- `rejectLease()`
- `getPendingApprovals()`
### 3. Lease Finalization Mechanism (HIGH PRIORITY)
- [ ] Implement lease activation on approval
- [ ] Ensure proper record linking (tenant_id, lease_id)
- [ ] Update tenant invite to reference approved lease
- [ ] Set up access rights and permissions
- [ ] Create payment schedules and reminders
- [ ] Validate data integrity
### 4. Tenant Invitation Page Updates (MEDIUM PRIORITY)
- [ ] Update `/tenant/invite/[invite_id].tsx` to check lease status
- [ ] Add status-based UI states:
- No lease: "Start Lease" button
- Pending: "Pending Landlord Approval"
- Approved: "Lease Approved - Continue"
- Rejected: "Lease Rejected" with contact info
- [ ] Add progress indicator showing approval steps
- [ ] Update POST handler to call approval API
### 5. Landlord Notifications (MEDIUM PRIORITY)
- [ ] Create `notificationService.ts` for centralized notifications
- [ ] Implement email templates:
- "New Lease Approval Required"
- "Lease Approved" confirmation
- "Lease Rejected" confirmation
- [ ] Add dashboard notifications
- [ ] Integrate with user preference system
### 6. Landlord Dashboard View (MEDIUM PRIORITY)
- [ ] Add "Pending Lease Approvals" section to dashboard
- [ ] Create approval cards with property/tenant details
- [ ] Add approval/rejection interface
- [ ] Update navigation with approval badge
- [ ] Create dedicated `/landlord/approvals` page
### 7. Testing (LOW PRIORITY)
- [ ] Unit tests for lease service functions
- [ ] Integration tests for API endpoints
- [ ] E2E tests for complete approval workflow
- [ ] UI tests for dashboard and invite page
## Verification Steps
After each major component, run:
```bash
deno check <modified_ts_file>
deno fmt <modified_ts_file>
deno lint <modified_ts_file>
```
Note: `deno check` only works on TypeScript files (.ts), not Markdown files (.md).
## Workflow Summary
1. Tenant clicks "Start Lease" → Creates lease with `approval_status: 'pending_approval'`
2. Landlord receives notification → Dashboard shows pending approval
3. Landlord reviews and approves/rejects → Updates lease status
4. System finalizes lease → Links records, sets up payments, grants access
## Files to Modify
- `db/schema.ts` - Add approval fields
- `services/leaseService.ts` - Add approval functions
- `routes/tenant/invite/[invite_id].tsx` - Update UI and logic
- `routes/landlord/dashboard/index.tsx` - Add pending approvals
- `routes/api/lease/` - Create approval endpoints
- `services/notificationService.ts` - New notification service
## Success Criteria
- [ ] All lease activations require landlord approval
- [ ] Tenants see clear approval status
- [ ] Landlords can easily review and approve/reject
- [ ] Notifications are sent reliably
- [ ] Lease finalization works correctly
- [ ] All tests pass

View File

@ -0,0 +1,64 @@
CREATE TABLE "reminders" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"lease_id" text,
"reminder_type" text NOT NULL,
"title" text NOT NULL,
"description" text,
"due_date" bigint NOT NULL,
"is_completed" boolean DEFAULT false,
"created_on" bigint,
"updated_on" bigint
);
--> statement-breakpoint
CREATE TABLE "tenant_invites" (
"id" text PRIMARY KEY NOT NULL,
"landlord_id" text,
"property_id" text,
"lease_id" text,
"available_on" bigint,
"invited_emails" text,
"created_on" bigint,
"updated_on" bigint
);
--> statement-breakpoint
CREATE TABLE "web_tokens" (
"token_id" varchar(64) PRIMARY KEY NOT NULL,
"state_id" varchar(36) NOT NULL,
"user_id" text NOT NULL,
"token_type" text NOT NULL,
"token_value" text NOT NULL,
"expires_on" bigint NOT NULL,
"created_on" bigint NOT NULL,
"updated_on" bigint NOT NULL,
"last_used_on" bigint,
"is_active" boolean DEFAULT true,
"metadata" json
);
--> statement-breakpoint
ALTER TABLE "brain_question_progress" ADD COLUMN "current_mode" text DEFAULT 'photo-see-bisaya' NOT NULL;--> statement-breakpoint
ALTER TABLE "brain_question_progress" ADD COLUMN "mode_index" integer DEFAULT 0;--> statement-breakpoint
ALTER TABLE "brain_question_progress" ADD COLUMN "consecutive_first_try" integer DEFAULT 0;--> statement-breakpoint
ALTER TABLE "brain_question_progress" ADD COLUMN "is_review_only" boolean DEFAULT false;--> statement-breakpoint
ALTER TABLE "leases" ADD COLUMN "default_payment_method_id" text;--> statement-breakpoint
ALTER TABLE "messages" ADD COLUMN "parent_message_id" text;--> statement-breakpoint
ALTER TABLE "messages" ADD COLUMN "attachments_json" json;--> statement-breakpoint
ALTER TABLE "properties" ADD COLUMN "default_payment_method_id" text;--> statement-breakpoint
ALTER TABLE "quiz_configs" ADD COLUMN "tab_name" text;--> statement-breakpoint
ALTER TABLE "quiz_configs" ADD COLUMN "tab_index" integer DEFAULT 0;--> statement-breakpoint
ALTER TABLE "quiz_configs" ADD COLUMN "list_index" integer DEFAULT 0;--> statement-breakpoint
ALTER TABLE "quiz_questions" ADD COLUMN "question_index" integer DEFAULT 0;--> statement-breakpoint
ALTER TABLE "tenant_applications" ADD COLUMN "document_urls_json" json;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "onboarded_landlord" boolean DEFAULT false;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "onboarded_tenant" boolean DEFAULT false;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "notification_preferences_json" json;--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "payment_preferences_json" json;--> statement-breakpoint
ALTER TABLE "reminders" ADD CONSTRAINT "reminders_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "reminders" ADD CONSTRAINT "reminders_lease_id_leases_id_fk" FOREIGN KEY ("lease_id") REFERENCES "public"."leases"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "tenant_invites" ADD CONSTRAINT "tenant_invites_landlord_id_users_id_fk" FOREIGN KEY ("landlord_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "tenant_invites" ADD CONSTRAINT "tenant_invites_property_id_properties_id_fk" FOREIGN KEY ("property_id") REFERENCES "public"."properties"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "tenant_invites" ADD CONSTRAINT "tenant_invites_lease_id_leases_id_fk" FOREIGN KEY ("lease_id") REFERENCES "public"."leases"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "web_tokens" ADD CONSTRAINT "web_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "leases" ADD CONSTRAINT "leases_default_payment_method_id_payment_methods_id_fk" FOREIGN KEY ("default_payment_method_id") REFERENCES "public"."payment_methods"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "properties" ADD CONSTRAINT "properties_default_payment_method_id_payment_methods_id_fk" FOREIGN KEY ("default_payment_method_id") REFERENCES "public"."payment_methods"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "brain_question_progress" DROP COLUMN "mode";

View File

@ -0,0 +1,8 @@
-- Migration: Add lease_id column to tenant_invites table
ALTER TABLE "tenant_invites" ADD COLUMN "lease_id" text REFERENCES "leases"("id");
--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "tenant_invites_lease_id_idx"
ON "tenant_invites" ("lease_id");

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,13 @@
"when": 1765422865294, "when": 1765422865294,
"tag": "0000_gifted_stepford_cuckoos", "tag": "0000_gifted_stepford_cuckoos",
"breakpoints": true "breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1769631945820,
"tag": "0001_spicy_sunset_bain",
"breakpoints": true
} }
] ]
} }