Our portal streamlines leasing with digital signatures, automates smart lock access, and enables one-tap reporting for disturbances. By integrating AI escalation, smart package lockers, and guest parking permits, we boost tenant satisfaction and retention.
| Next.js | Appwrite | Supabase | React.js |
|---|---|---|---|
| Next Docs | Appwrite Docs | Supabase Docs | React Docs |
![]() Cass Cavazos |
![]() Joe Aguado |
![]() Damian Padilla |
![]() Tatiana Bertazoli |
![]() Andrew Smith |
![]() Staci Southerland |
![]() Danny Thompson (Tech Lead) |
- π Introduction
- ποΈ Architecture Overview
- π οΈ Technology Stack
- πΎ Database Schema
- π Authentication Flow
- β¨ Key Features
- π API Structure
- π§© Component Structure
- π Data Flow
- π Deployment
- π» Jira/Git Workflow
- π’ Color Branding
Tenant App is a comprehensive property management application designed to streamline interactions between property managers and tenants. The application provides a modern solution to common property management challenges, offering features such as digital lease signing, smart door access, package locker management, guest parking passes, noise reporting, and messaging.
The application follows a modern web architecture using Next.js, which provides server-side rendering capabilities and API routes. The architecture can be broken down into the following key components:
| Component | Description |
|---|---|
| Frontend | React-based UI components using Next.js framework |
| Backend API | Next.js API routes for handling server-side logic |
| Database | PostgreSQL database managed through Prisma ORM |
| Authentication | Appwrite for user authentication and management |
| PDF Generation | PDF-lib for lease document generation |
The application follows a client-server architecture where the frontend communicates with the backend API, which in turn interacts with the database and external services.
| Technology | Version/Description |
|---|---|
| Framework | Next.js 15.2.1 |
| UI Library | React 19.0.0 |
| Form Management | @tanstack/react-form |
| Icons | Lucide React |
| Styling | Tailwind CSS |
| Technology | Version/Description |
|---|---|
| API Routes | Next.js API routes |
| Database ORM | Prisma 6.5.0 |
| Database | PostgreSQL (via Postgres.js) |
| Authentication | Appwrite |
| PDF Generation | PDF-lib |
| Tool | Purpose |
|---|---|
| TypeScript | Type checking |
| Jest | Testing framework |
| React Testing Library | Component testing |
| ESLint | Code linting |
The application uses a PostgreSQL database with the following key models:
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| appwriteId | String | External auth ID |
| firstName | String | User's first name |
| lastName | String | User's last name |
| String | User's email address | |
| phoneNumber | String | User's phone number |
| apartmentNumber | String | Apartment identifier |
| image | String | Profile image URL |
| leaseId | String | Associated lease ID |
| userRole | Enum | User role (ADMIN, TENANT, etc.) |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Record update timestamp |
Relationships: Has one Lease, has many ParkingPass, SmartDoorKey, PackageLocker, and Notification records
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| managementCompanyName | String | Property management company |
| addressId | String | Associated address ID |
| propertyName | String | Name of the property |
| phoneNumber | String | Contact phone number |
| String | Contact email | |
| websiteURL | String | Property website |
| propertyImage | String | Property image URL |
| description | String | Property description |
| propertyManagerName | String | Manager's name |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Record update timestamp |
Relationships: Has one Address, has many Amenities and Leases
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| propertyId | String | Associated property |
| firstName | String | Tenant's first name |
| lastName | String | Tenant's last name |
| String | Tenant's email | |
| apartmentNumber | String | Apartment identifier |
| pets | Boolean | Whether pets are allowed |
| governmentId | String | Government ID reference |
| socialSecurity | String | SSN reference |
| leaseStart | DateTime | Lease start date |
| leaseEnd | DateTime | Lease end date |
| monthlyRent | Decimal | Monthly rent amount |
| securityDeposit | Decimal | Security deposit amount |
| leaseStatus | Enum | Status (ACTIVE, EXPIRED, PENDING) |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Record update timestamp |
Relationships: Belongs to Property, has many Users
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| userId | String | Associated user ID |
| make | String | Vehicle make |
| model | String | Vehicle model |
| color | String | Vehicle color |
| licensePlate | String | License plate number |
| parkingPassNumber | String | Unique pass identifier |
| createdAt | DateTime | Record creation timestamp |
| expirationDate | DateTime | Pass expiration date |
Relationships: Belongs to User
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| senderId | String | Sender user ID |
| receiverId | String | Receiver user ID |
| notificationType | Enum | Type of notification |
| subject | String | Notification subject |
| message | String | Notification content |
| status | Enum | Status (READ, UNREAD) |
| priority | Enum | Priority (LOW, MEDIUM, HIGH) |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Record update timestamp |
Relationships: Belongs to sender User and receiver User
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| userId | String | Associated user ID |
| accessCode | String | Door access code |
| createdAt | DateTime | Record creation timestamp |
| expirationDate | DateTime | Code expiration date |
| lastAccessed | DateTime | Last access timestamp |
| lockStatus | Boolean | Lock status (locked/unlocked) |
Relationships: Belongs to User
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| userId | String | Associated user ID |
| lockerNumber | String | Locker identifier |
| packageLockerStatus | Enum | Status (READY_FOR_PICKUP, PICKED_UP) |
| accessCode | String | Locker access code |
| createdAt | DateTime | Record creation timestamp |
| lastAcessed | DateTime | Last access timestamp |
Relationships: Belongs to User
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| address | String | Street address |
| suiteNumber | Int | Suite or apartment number |
| city | String | City name |
| state | String | State or province |
| zipCode | String | Postal code |
| country | String | Country name |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Record update timestamp |
Relationships: Has one Property
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| amenityName | String | Name of the amenity |
| description | String | Amenity description |
| location | String | Location within property |
| availabilityStatus | Enum | Status (AVAILABLE, UNAVAILABLE) |
| requiresAccessCode | Boolean | Whether access code is required |
| createdAt | DateTime | Record creation timestamp |
| updatedAt | DateTime | Record update timestamp |
| propertyId | String | Associated property ID |
Relationships: Belongs to Property
| Field | Type | Description |
|---|---|---|
| id | String | Unique identifier |
| fullName | String | Contact name |
| String | Contact email | |
| phoneNumber | String | Contact phone |
| subject | String | Message subject |
| message | String | Message content |
| createdAt | DateTime | Record creation timestamp |
The application uses Appwrite for authentication. The authentication flow works as follows:
| Step | Description |
|---|---|
| 1 | Users register or log in through the login page |
| 2 | Authentication state is managed through the AuthContext |
| 3 | User tokens are stored and managed for authenticated API requests |
| 4 | Different user roles determine access to different features |
- Generate and sign lease agreements digitally
- Track lease status (ACTIVE, EXPIRED, PENDING)
- Store lease details including rent, security deposit, and lease terms
- Generate unique access codes for door entry
- Manage expiration dates for temporary access
- Track door access history
- Assign lockers for package delivery
- Generate access codes for package pickup
- Track package status (READY_FOR_PICKUP, PICKED_UP)
- Generate temporary parking passes for guests
- Track vehicle information and pass expiration
- Verify passes through unique codes
- Send and receive notifications between tenants and management
- Support different notification types (COMPLAINT, REPAIR, NOISE_COMPLAINT, GENERAL, PACKAGE, PARKING_PASS, LEASE, MANAGEMENT)
- Prioritize notifications (LOW, MEDIUM, HIGH)
- Direct messaging between tenants and property management
- Thread-based conversation tracking
- Message search functionality
- Track property amenities and their availability
- Manage access codes for restricted amenities
The application uses Next.js API routes organized by feature:
| API Endpoint | Purpose |
|---|---|
/api/admin/notifications |
Manage administrative notifications |
/api/contact |
Handle contact form submissions from prospective tenants |
/api/lease |
Manage lease creation, signing, and retrieval |
/api/noise |
Handle noise complaint submissions and tracking |
/api/notifications |
Manage general notification system for all users |
/api/parking |
Handle guest parking pass creation and validation |
/api/property |
Manage property information and amenities |
/api/users |
Handle user registration, profile management, and authentication |
The application uses a component-based architecture with the following key components:
Header: Main navigation headerFooter: Site footer with links and informationLayout: Main layout wrapper for consistent page structure
LandingPage: Homepage with marketing contentDashboard: Tenant dashboard with access to featuresLogin: User authentication pageRegister: New user registration
FeatureHighlight: Showcases key application featuresFeatureCard: Individual feature display cardContactUs: Contact form for prospective tenantsParkingPassForm: Form for creating guest parking passesSmartDoorAccess: Interface for door access managementPackageLockerAccess: Interface for package locker managementLeaseManagement: Interface for lease viewing and signingMessaging: Messaging interface for tenant-management communication
Hero: Hero section for landing pageHeroPool: Secondary hero section with image
| Step | Description |
|---|---|
| 1 | User submits registration form |
| 2 | Data is sent to Appwrite for authentication |
| 3 | User record is created in the database |
| 4 | Authentication token is returned and stored |
| 5 | User is redirected to dashboard |
| Step | Description |
|---|---|
| 1 | Tenant fills out parking pass form |
| 2 | Form data is validated client-side |
| 3 | Data is sent to /api/parking endpoint |
| 4 | Parking pass record is created in database |
| 5 | Unique pass code is generated and returned |
| 6 | Pass details are displayed to tenant |
| Step | Description |
|---|---|
| 1 | Admin creates notification through admin interface |
| 2 | Notification is stored in database with appropriate type and priority |
| 3 | Notification appears in tenant's notification list |
| 4 | Tenant can mark notification as read |
| 5 | Notification status is updated in database |
| Step | Description |
|---|---|
| 1 | Admin enters lease details for tenant |
| 2 | Data is sent to lease generation API |
| 3 | PDF lease document is created using PDF-lib |
| 4 | Lease record is created in database |
| 5 | Tenant receives notification about new lease |
| 6 | Tenant can view and digitally sign lease |
The application is designed to be deployed using modern cloud infrastructure:
| Component | Deployment Solution |
|---|---|
| Frontend and API | Next.js application on platforms like Vercel or Netlify |
| Database | PostgreSQL database hosted on a cloud provider (e.g., Supabase, AWS RDS, Digital Ocean) |
| Authentication | Appwrite services for user authentication |
| File Storage | Cloud storage for property images and documents |
| Environment Variables | Configured for different environments (development, production) |
- In Jira, find a ticket to work on
- Assign it to yourself and mark it as 'In Progress'
-
Make sure your local repo is up to date (make sure you have main checked out locally first):
git pull origin main
-
Create a new branch locally. Make sure to only use the Jira ticket:
git checkout -b AP-12345
-
Make your changes and then stage them. Commits should be either feat, chore, or fix. Make sure the Jira ticket is at the end in parentheses:
git commit -m 'feat: add super awesome modal (AP-12345)'or...
git commit -m "chore: add bg color for super awesome modal (AP-12345)"or...
git commit -m "fix: center modal (AP-12345)"
-
Sync the remote repo with with your local repo and your new branch:
git push origin AP-12345
-
Under (https://github.com/TheDThompsonDev/tenant-app/branches) you should find the branch you just pushed. Click on it.
-
Click "Compare & pull request".
-
Make sure base is set to main at the top.
-
Adjust the title as needed and add a description.
-
Add reviewers (2) by clicking the gear.
-
Click "Create pull request".
-
Once the PR is approved, the assignee (you) should complete the pull request by merging to main and delete the branch.
-
Go back to Jira and change ticket status to done.
In order to use the in-line color schema within any front-end component, under className, use one of the following color configuration names:
primary-greensecondary-bluealternate-greenprimary-blacksecondary-dark-grayalternate-grayalternate-light-gray
These can be applied to background colors, text colors, and border colors using Tailwind's utility classes.
<div className='bg-primary-green p-4'>
This div has a primary green background.
</div>/api/generate-and-send/route.js
This generates a lease and sends it to Documenso. It's triggered when admin fills out the lease form.
Steps:
- Collects lease details (landlord, tenant, address, rent, dates).
- Generates a PDF using pdf-lib.
- Sends the PDF to Documenso.
- Triggers an email to the tenant (once sending is successful).
- Redirects to /confirmation?id={documentId} after successful submission.
/api/document-status/route.js
Purpose: Fetches the current status of a lease document from Documenso.
Triggered by: The /confirmation page to check if the tenant has signed.
Steps:
- Takes a documentId and queries Documenso.
- Returns the status (DRAFT, PENDING SIGNATURE, SIGNED, etc.).
- Used for displaying lease progress on the dashboard.







