HomeMatch is a real estate platform built with Django REST Framework and a static HTML/CSS/JavaScript frontend. The system supports property listing, authentication, favorites, reviews, image upload and AI-assisted visual analysis of property photos.
The project currently includes a working backend API, asynchronous image analysis with Celery, local or Cloudflare R2 image storage, and a frontend prepared to integrate with a backend natural-language search module.
- JWT authentication with register, login, logout and token refresh.
- User profile page.
- Property listing and detail pages.
- Property CRUD through the REST API.
- Objective property filters by city, neighborhood, price, area, rooms, condominium features, type and purpose.
- Property photo upload.
- Local media storage for development.
- Cloudflare R2 support for remote image storage.
- AI photo analysis using a vision model.
- Per-photo subjective visual attributes.
- Aggregated per-property subjective visual attributes.
- User favorites.
- Reviews with ratings and comments.
- Average rating per property.
- Static frontend integrated with the API.
- Frontend prepared for backend-owned natural-language search.
- Real‑time notifications for key events: when a favourited property's price changes, when someone reviews one of your properties, or when the AI finishes analysing your property photos. Notifications are delivered live over WebSockets using Django Channels.
- Notification API to list your notifications (
GET /api/notifications/) and mark them as read (PATCH /api/notifications/{id}/). - Test suite with pytest and pytest‑django covering authentication, property CRUD, reviews and favourites. Run
pip install -r requirements-dev.txtandpytestto execute all tests with a coverage report.
HomeMatch/
├── apps/
│ ├── users/ # Authentication, profile, favorites
│ ├── properties/ # Properties, photos, filters, reviews
│ ├── ai_analysis/ # Vision model integration and visual attributes
│ └── search/ # Natural-language search integration point
├── config/ # Django settings and root URLs
├── frontend/ # Static HTML/CSS/JS frontend
├── docs/
├── tools/
├── docker-compose.yaml
├── Dockerfile
└── requirements.txtProperty photo is uploaded
-> image is saved locally or in Cloudflare R2
-> Celery task analyzes the photo with a vision model
-> PhotoSubjectiveAttribute records are saved
-> PropertySubjectiveAttribute aggregates are updated
-> frontend displays the visual analysis on the details page| Layer | Technology |
|---|---|
| Backend | Python 3.12 + Django 5.2 |
| API | Django REST Framework |
| Authentication | JWT / Simple JWT |
| Database | PostgreSQL |
| Async tasks | Celery |
| Broker | Redis |
| Storage | Local media or Cloudflare R2 |
| AI | Gemini SDK for local files; OpenAI-compatible client for remote URLs |
| Frontend | Static HTML, CSS and JavaScript modules |
| Containers | Docker + Docker Compose |
The frontend is a static multi-page application. It does not require React, Vite or npm.
Expected structure:
frontend/
├── index.html
├── imoveis.html
├── detalhes.html
├── login.html
├── cadastro.html
├── perfil.html
├── styles.css
└── assets/
├── api.js
└── homematch-logo.jpegRun it locally with:
python -m http.server 5500 -d frontendThen open:
http://localhost:5500The frontend expects the backend at:
http://localhost:8000Image URLs returned as /media/... must be resolved against the backend base URL.
The frontend is prepared to call this backend-owned natural-language search endpoint:
GET /api/search/properties/?q=<query>&city=<city>&type=<type>&property_purpose=<purpose>The frontend does not interpret natural language and does not rank semantic results. It only sends the query and objective filters, then renders the properties in the order returned by the backend.
The AI module stores subjective attributes at two levels:
PhotoSubjectiveAttribute
PropertySubjectiveAttributeExamples of visual attributes:
aesthetics.color.brightness
aesthetics.color.visual_warmth
current_state.ventilation
current_state.cleanliness
current_state.structural_integrity
livability.coziness
livability.spaciousness
livability.verdancy
aesthetics.architecture.contemporary
aesthetics.architecture.minimalistFor local development, use:
USE_LOCAL_STORAGE=True
AI_MODEL=gemini-2.5-flashThe configured model must support generateContent and image input.
HomeMatch agora suporta notificações em tempo real através de WebSockets. Quando um usuário favorita um imóvel, ele será avisado imediatamente caso:
- O preço do imóvel seja atualizado.
- Uma nova review seja feita para esse imóvel.
- A análise de IA de uma foto do imóvel seja concluída.
- O backend utiliza Django Channels com Redis como channel layer para gerenciar conexões WebSocket.
- Um serviço adicional
channels_workerfoi adicionado aodocker-compose.yamlpara processar mensagens WebSocket. - A URL do WebSocket é:
ws://<host>:8001/ws/notifications/?token=<access_token>. - O token de acesso JWT deve ser passado como parâmetro de consulta (
token=) para autenticar a conexão.
Além das mensagens em tempo real, as notificações são persistidas no banco de dados e podem ser acessadas via API:
| Método | Endpoint | Descrição |
|---|---|---|
GET |
/api/notifications/ |
Lista todas as notificações do usuário autenticado |
PATCH |
/api/notifications/{id}/ |
Marca uma notificação específica como lida |
As notificações armazenam o tipo de evento, a mensagem e um campo read indicando se já foram visualizadas.
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/users/register/ |
Register user |
POST |
/api/users/login/ |
Login and return JWT tokens |
POST |
/api/users/token/refresh/ |
Refresh access token |
POST |
/api/users/logout/ |
Logout / blacklist refresh token |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/users/me/ |
Get current user |
PATCH |
/api/users/me/ |
Update current user |
GET |
/api/users/favorites/ |
List favorites |
POST |
/api/users/favorites/ |
Add favorite |
DELETE |
/api/users/favorites/ |
Remove favorite |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/properties/ |
List properties with filters |
POST |
/api/properties/ |
Create property |
GET |
/api/properties/{id}/ |
Property details |
PATCH |
/api/properties/{id}/ |
Update property |
DELETE |
/api/properties/{id}/ |
Delete property |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/properties/{id}/photos/ |
Upload property photo |
DELETE |
/api/properties/photos/{id}/ |
Delete property photo |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/properties/{id}/reviews/ |
List reviews |
POST |
/api/properties/{id}/reviews/ |
Create review |
PATCH |
/api/properties/{id}/reviews/{review_id}/ |
Edit review |
DELETE |
/api/properties/{id}/reviews/{review_id}/ |
Delete review |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/search/properties/ |
Natural-language property search |
Supported objective filters for /api/properties/ and expected for /api/search/properties/:
?min_price=1000&max_price=5000
?min_area=50&max_area=150
?city=Natal
?neighborhood=Ponta+Negra
?bedrooms=2
?bathrooms=1
?parking_spots=1
?type=A
?property_purpose=R
?condo_gym=true
?condo_pool=true
?living_room=true
?garden=truegit clone https://github.com/DevlTz/HomeMatch.git
cd HomeMatchcp .env.example .envExample local .env:
SECRET_KEY=local-dev-secret
DEBUG=True
DB_NAME=homematch_db
DB_USER=postgres
DB_PASSWORD=postgres
DB_HOST=db
DB_PORT=5432
USE_LOCAL_STORAGE=True
R2_ACCESS_KEY_ID=
R2_SECRET_ACCESS_KEY=
R2_BUCKET_NAME=
R2_ACCOUNT_ID=
AI_API_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
AI_API_KEY=your-google-ai-studio-key
AI_MODEL=gemini-2.5-flash
GOOGLE_PLACES_API_KEY=dummy-key-for-local-devdocker compose up --build -ddocker compose exec web python manage.py migratedocker compose exec web python manage.py createsuperuserpython -m http.server 5500 -d frontendFrontend: http://localhost:5500
API: http://localhost:8000
Django Admin: http://localhost:8000/adminView logs:
docker compose logs -f web celery_workerCheck AI settings:
docker compose exec web python manage.py shell -c "
from django.conf import settings
print('USE_LOCAL_STORAGE =', settings.USE_LOCAL_STORAGE)
print('AI_MODEL =', settings.AI_MODEL)
print('AI_API_KEY set =', bool(settings.AI_API_KEY))
"List available Gemini models:
docker compose exec web python manage.py shell -c "
import google.generativeai as genai
from django.conf import settings
genai.configure(api_key=settings.AI_API_KEY)
for model in genai.list_models():
methods = getattr(model, 'supported_generation_methods', [])
if 'generateContent' in methods:
print(model.name)
"Change admin password:
docker compose exec web python manage.py changepassword <admin-email-or-username>This project includes an automated test suite using pytest and pytest-django. The tests cover authentication, property creation and management, reviews, and favorites. To run the tests with a coverage report:
-
Install dependencys:
pip install -r requirements-dev.txt
-
Run the migrations in a test database (this is done automatically by pytest-django):
docker compose exec web python manage.py migrate -
Run the tests:
pytest
-
To check code coverage, use:
pytest --cov=apps
The pytest.ini file is already configured to point to the Django settings (DJANGO_SETTINGS_MODULE=config.settings) and to use the coverage option automatically when needed.
Reusable fixtures (advertiser user, regular user, tokens, property factory) are defined in conftest.py. The test database is isolated and uses the TEST configuration in settings.py to avoid conflicts with the development database.
Run reports:
pip install -r tools/requirements-dev.txt
./tools/run_reports.sh| Name | GitHub |
|---|---|
| Kauã do Vale Ferreira | @DevlTz |
| Luisa Ferreira de Souza Santos | @luisaferreirass |
| Lucas Graziano dos Santos Anselmo | @lucasanselmocc |
Software Engineering course project @UFRN