Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Tenantly - Property Rental Management System
# 🏠 Tenantly - Property Rental Management System

A comprehensive tenant management system designed for the Bangladesh market, focusing on property rental management.

## Overview
## 📋 Overview

Tenantly is a robust, multi-service platform built to streamline property management. It handles everything from tenant onboarding and lease management to automated billing and notifications.

- **Backend API**: High-performance Go (Gin) service for core logic.
- **Frontend**: Modern Angular application with a responsive dashboard.
- **Notification Service**: Background worker built with .NET 8 for SMS/Email alerts.
- **Notification Service**: Background worker built with .NET for SMS/Email alerts.

## Quick Start
## 🚀 Quick Start

The fastest way to get started is using Docker Compose.

### Prerequisites
### 🛠️ Prerequisites

- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
- [Docker Compose](https://docs.docker.com/compose/install/)

### Setup
### ⚙️ Setup

1. **Clone the repository**
2. **Setup environment variables**:
Expand All @@ -36,7 +36,7 @@ The applications will be available at:
- **Backend API**: `http://localhost:8080/api/v1`
- **PostgreSQL**: `localhost:5432`

## Project Structure
## 📂 Project Structure

For detailed documentation, please refer to the specific component directories:

Expand All @@ -46,15 +46,15 @@ For detailed documentation, please refer to the specific component directories:
| **Notification Service** | .NET Background Service | [backend/notification-service](./src/backend/notification-service/README.md) |
| **Frontend** | Angular Application | [frontend](./src/frontend/README.md) |

## Features
## Features

- **Shop Management**: Track properties, units, and occupancy.
- **Property Management**: Track properties, buildings, units, and occupancy.
- **Tenant Management**: Profiles, contact info, and history.
- **Lease Processing**: Terms, deposits, and automated renewals.
- **Payments**: Multi-channel payment tracking and invoicing.
- **Automated Alerts**: SMS and Email reminders for rent and renewals.
- **Localization**: Native support for Bengali and BDT (৳).
- **CI/CD**: Automated linting and formatting via GitHub Actions.
- **CI/CD**: Automated linting, formatting, and deployment via GitHub Actions.

## 🤝 Contributing

Expand Down
10 changes: 2 additions & 8 deletions src/backend/api/internal/handlers/property_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,7 @@ func (h *PropertyHandler) CreateProperty(c *gin.Context) {
return
}

c.JSON(http.StatusCreated, gin.H{
"message": "Property created successfully",
"property": property,
})
c.JSON(http.StatusCreated, property)
}

// GetProperties retrieves properties with filtering and pagination
Expand Down Expand Up @@ -218,10 +215,7 @@ func (h *PropertyHandler) UpdateProperty(c *gin.Context) {
return
}

c.JSON(http.StatusOK, gin.H{
"message": "Property updated successfully",
"property": property,
})
c.JSON(http.StatusOK, property)
}

// DeleteProperty soft deletes a property
Expand Down
55 changes: 55 additions & 0 deletions src/backend/api/internal/models/columns/building_columns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package columns

// Building table and column names
const (
BuildingTable = "buildings"
BuildingID = "id"
BuildingPropertyID = "property_id"
BuildingName = "building_name"
BuildingCode = "building_code"
BuildingType = "building_type"
BuildingTotalFloors = "total_floors"
BuildingHasElevator = "has_elevator"
BuildingConstructionYear = "construction_year"
BuildingMetadata = "metadata"
BuildingActiveStatus = "active_status"
BuildingCreatedAt = "created_at"
BuildingUpdatedAt = "updated_at"
)

// BuildingAllColumns returns a comma-separated list of all building columns
// for use in SELECT statements
func BuildingAllColumns() string {
return BuildingID + ", " +
BuildingPropertyID + ", " +
BuildingName + ", " +
BuildingCode + ", " +
BuildingType + ", " +
BuildingTotalFloors + ", " +
BuildingHasElevator + ", " +
BuildingConstructionYear + ", " +
BuildingMetadata + ", " +
BuildingActiveStatus + ", " +
BuildingCreatedAt + ", " +
BuildingUpdatedAt
}

// BuildingSelectWithAlias returns all building columns with a table alias
// Example: BuildingSelectWithAlias("b") returns "b.id, b.property_id, ..."
func BuildingSelectWithAlias(alias string) string {
if alias == "" {
return BuildingAllColumns()
}
return alias + "." + BuildingID + ", " +
alias + "." + BuildingPropertyID + ", " +
alias + "." + BuildingName + ", " +
alias + "." + BuildingCode + ", " +
alias + "." + BuildingType + ", " +
alias + "." + BuildingTotalFloors + ", " +
alias + "." + BuildingHasElevator + ", " +
alias + "." + BuildingConstructionYear + ", " +
alias + "." + BuildingMetadata + ", " +
alias + "." + BuildingActiveStatus + ", " +
alias + "." + BuildingCreatedAt + ", " +
alias + "." + BuildingUpdatedAt
}
55 changes: 55 additions & 0 deletions src/backend/api/internal/models/columns/property_columns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package columns

// Property table and column names
const (
PropertyTable = "properties"
PropertyID = "id"
PropertyName = "property_name"
PropertyCode = "property_code"
PropertyAddress = "address"
PropertyCity = "city"
PropertyPostalCode = "postal_code"
PropertyType = "property_type"
PropertyTotalBuildings = "total_buildings"
PropertyMetadata = "metadata"
PropertyActive = "active"
PropertyCreatedAt = "created_at"
PropertyUpdatedAt = "updated_at"
)

// PropertyAllColumns returns a comma-separated list of all property columns
// for use in SELECT statements
func PropertyAllColumns() string {
return PropertyID + ", " +
PropertyName + ", " +
PropertyCode + ", " +
PropertyAddress + ", " +
PropertyCity + ", " +
PropertyPostalCode + ", " +
PropertyType + ", " +
PropertyTotalBuildings + ", " +
PropertyMetadata + ", " +
PropertyActive + ", " +
PropertyCreatedAt + ", " +
PropertyUpdatedAt
}

// PropertySelectWithAlias returns all property columns with a table alias
// Example: PropertySelectWithAlias("p") returns "p.id, p.property_name, ..."
func PropertySelectWithAlias(alias string) string {
if alias == "" {
return PropertyAllColumns()
}
return alias + "." + PropertyID + ", " +
alias + "." + PropertyName + ", " +
alias + "." + PropertyCode + ", " +
alias + "." + PropertyAddress + ", " +
alias + "." + PropertyCity + ", " +
alias + "." + PropertyPostalCode + ", " +
alias + "." + PropertyType + ", " +
alias + "." + PropertyTotalBuildings + ", " +
alias + "." + PropertyMetadata + ", " +
alias + "." + PropertyActive + ", " +
alias + "." + PropertyCreatedAt + ", " +
alias + "." + PropertyUpdatedAt
}
58 changes: 58 additions & 0 deletions src/backend/api/internal/models/columns/unit_columns.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package columns

// Unit table and column names
const (
UnitTable = "units"
UnitID = "id"
UnitBuildingID = "building_id"
UnitPropertyID = "property_id"
UnitNumber = "unit_number"
UnitName = "unit_name"
UnitFloor = "floor"
UnitSection = "section"
UnitType = "unit_type"
UnitMonthlyRent = "monthly_rent"
UnitMetadata = "metadata"
UnitActive = "active"
UnitCreatedAt = "created_at"
UnitUpdatedAt = "updated_at"
)

// UnitAllColumns returns a comma-separated list of all unit columns
// for use in SELECT statements
func UnitAllColumns() string {
return UnitID + ", " +
UnitBuildingID + ", " +
UnitPropertyID + ", " +
UnitNumber + ", " +
UnitName + ", " +
UnitFloor + ", " +
UnitSection + ", " +
UnitType + ", " +
UnitMonthlyRent + ", " +
UnitMetadata + ", " +
UnitActive + ", " +
UnitCreatedAt + ", " +
UnitUpdatedAt
}

// UnitSelectWithAlias returns all unit columns with a table alias
// Example: UnitSelectWithAlias("u") returns "u.id, u.building_id, ..."
func UnitSelectWithAlias(alias string) string {
if alias == "" {
return UnitAllColumns()
}
return alias + "." + UnitID + ", " +
alias + "." + UnitBuildingID + ", " +
alias + "." + UnitPropertyID + ", " +
alias + "." + UnitNumber + ", " +
alias + "." + UnitName + ", " +
alias + "." + UnitFloor + ", " +
alias + "." + UnitSection + ", " +
alias + "." + UnitType + ", " +
alias + "." + UnitMonthlyRent + ", " +
alias + "." + UnitMetadata + ", " +
alias + "." + UnitActive + ", " +
alias + "." + UnitCreatedAt + ", " +
alias + "." + UnitUpdatedAt
}
Loading