[Jane Dane]

Design decisions

Table of contents

Core Architecture and Data Model

Decision 01: Database Engine Choice – SQLite

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to choose a database system to persistently store and manage application data in RentTracker. Since our data structure was clearly relational — involving apartments, tenants, rental agreements, and monthly payments — we required a relational database. The choice had to support integration with Flask and suit the project scale and team expertise.

Decision

We chose SQLite as the database engine for the current version of the project. Reasons:

  • Our data model is strictly relational — easily mapped to SQL tables.
  • SQLite is lightweight, serverless, and integrates seamlessly with Flask.
  • Course materials and professor support focused on SQLite, lowering the learning curve.
  • For an MVP-stage application, SQLite provides sufficient functionality and performance.

Decision taken by: Denis Cercasin

Regarded options

We regarded two alternative options:

  • PostgreSQL
  • MySQL
Criterion SQLite PostgreSQL/MySQL
Integration with Flask ✔️ Native, simple ✔️ Requires some setup, but is “doable”
Relational structure ✔️ Fully supported ✔️ Fully supported
Learning curve ✔️ Easy, covered in course ❌ Additional overhead
Server setup ✔️ None (file-based) ❌ Requires database server
Scalability ❌ Limited ✔️ Better for scaling

Decision 02: Core Data Model - Table Structure

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to define a consistent and logical data model that reflects the domain of rental property management. The goal was to store all relevant information about apartments, tenants, their rental agreements, and payment tracking — in a way that is normalized, efficient, and easy to query.

Decision

We defined the following core tables:

  • apartments – uniquely identifies rental units.
  • tenants – stores personal details of tenants.
  • rental_agreements – models contracts between tenants and apartments, with start/end dates.
  • rent_payments – tracks monthly rent payments per agreement.

The structure is normalized and supports all necessary relationships (e.g., one-to-many between apartments and agreements). This design allows clear querying for reminders, overdue rents, tenant histories, support for future automation features like reminders.

Decision taken by: Denis Cercasin

Regarded options

We considered alternative structures such as:

  • Combining tenants and agreements (too limiting for contract history).
  • Tracking rent directly under tenants (not clear design and not scalable).

Decision 21: Use Shared Database with User-Based Row-Level Isolation

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

Initially, the app was built assuming a single user (landlord) managing data. As we moved toward multi-user support, we had to decide how to isolate user data to prevent cross-access.

Options included:

  • Creating a separate database per user,
  • Or enforcing row-level filtering within a shared database.

Decision

We chose to keep one shared relational database and enforce row-level isolation using a user_id foreign key on relevant tables (e.g., apartments, tenants, rental_agreements, payments).

We use current_user.id from Flask-Login to:

  • Filter all user-owned data in queries,
  • Assign ownership when creating new entries.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Separate DB per user ✔️ Full isolation ❌ Complex setup
❌ Not scalable
Shared DB + user_id (chosen) ✔️ Simple
✔️ Scalable
✔️ Works with Flask-Login
❌ Requires careful query filtering
No isolation (single user only) ✔️ Easiest for MVP ❌ Not secure
❌ No support for real users

Decision 24: Keep AUTOINCREMENT IDs with Gaps and Use Loop Index for UI Displays

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

When deleting a record (e.g., apartment with ID 3) and adding a new one, the database assigns a new ID (e.g., 4), leaving gaps in the sequence. This is default behavior when using AUTOINCREMENT.

Some users may find the missing IDs confusing if exposed directly in the interface.

Decision

We kept the default AUTOINCREMENT behavior for all primary keys. IDs are:

  • Unique,
  • Stable,
  • Not reused after deletion.

For UI tables (e.g., apartments, tenants), we show loop.index instead of raw database IDs to provide a clean, sequential display.

This avoids confusion, keeps logic simple, and follows best practices.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
✅ Keep AUTOINCREMENT (chosen) ✔️ Safe
✔️ Referential integrity
✔️ No surprises
❌ Gaps in raw ID sequence
Reset AUTOINCREMENT manually ✔️ Restores sequence ❌ Risky in production
❌ Breaks references
Assign custom IDs ✔️ Full control ❌ Complex
❌ Error-prone

Decision 25: Use Simple Primary Keys for rental_agreement and rent_payment

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to design primary keys for rental_agreement and rent_payment. The initial idea used composite keys (e.g., apartment_id + tenant_id) but this made it hard to:

  • Track agreement history over time,
  • Support overlapping tenants across months,
  • Record multiple payments from the same tenant.

Decision

We introduced simple, unique id primary keys in both tables:

rental_agreement:

  • Has its own id
  • Enforces one active agreement per apartment during a given date range
  • Supports multiple historical agreements (e.g., tenant history)

rent_payment:

  • Has its own id
  • Allows multiple payments per tenant (e.g., advance payments for several months)

This design avoids duplicates, allows flexibility, and improves query simplicity.

Decision taken by: Denis Cercasin

Regarded options

Table Option Pros Cons
rental_agreement id as PK (chosen) ✔️ Tracks history
✔️ Clean relations
❌ Requires overlap-check logic
  Composite PK (apartment+tenant) ✔️ Enforces uniqueness ❌ No history
❌ Can’t handle changing tenants
rent_payment id as PK (chosen) ✔️ Multiple payments allowed
✔️ Easy referencing
❌ More entries, requires validation logic
  Composite PK (month+tenant) ✔️ Enforces 1 payment/month ❌ Blocks prepayments
❌ Complex queries

Schema and Data Consistency

Decision 22: Resolve Tenant Info at Read-Time Instead of Storing in rent_payment

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

Originally, we stored the tenant_id directly in the rent_payment table. This required SQL logic to look up the active rental agreement (per apartment and month) during insertion. The logic assumed only one valid agreement at a time.

However, this approach:

  • Violated normalization principles,
  • Created unnecessary complexity during data insertion,
  • Risked inconsistency if rental agreements changed later.

Decision

We removed tenant_id from the rent_payment table and now resolve tenant data dynamically at read-time using a JOIN with the rental_agreement table.

This ensures:

  • Cleaner schema (normalized),
  • Historical accuracy (data doesn’t become stale if agreements change),
  • Correct tenant shown for past, current, and even future months.

Tenant selection is based on the agreement where:

DATE(?month) BETWEEN start_date AND IFNULL(end_date, DATE(?month))

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Store tenant_id in rent_payment ✔️ Easier querying later ❌ Redundant
❌ Risk of stale/invalid data
✅ Resolve tenant at read-time (chosen) ✔️ Accurate
✔️ Normalized
✔️ Works with changes
❌ Slightly more query logic

Decision 12: Store One Rent Payment Entry Per Month

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

Landlords often receive rent payments covering multiple months. We had to decide how to store such entries: as a single database row listing multiple months, or as separate entries — one per month — even if submitted at once.

Decision

We implemented multi-month rent selection in the UI, but store each month as a separate row in the database.

Reasons:

  • Clean, consistent data model (1 entry = 1 month)
  • Simplifies filtering, reminders, and statistics
  • Easier to support future automation (e.g., unpaid month alerts)
  • “Garbage IN = Garbage OUT” -> easy to use for future APIs

Decision taken by: Denis Cercasin, Caren Kedis

Regarded options

Option Pros Cons
One row for multiple months (comma-separated) ✔️ Simple to implement
✔️ Matches single action
❌ Hard to filter/group
❌ Not normalized
✅ One row per month (chosen) ✔️ Clean structure
✔️ Easy for analytics & reminders
❌ Slightly more logic needed

Decision 23: Resolve Foreign Key Relationships in SQL, Not in Templates

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to decide where to “translate” foreign keys (e.g., tenant_id, apartment_id) into human-readable names:

  • Inside the SQL query using JOINs
  • Or later in Jinja templates using manual lookups

Decision

We resolved all foreign key relationships (e.g., tenant name, apartment title) directly in SQL queries using JOINs.

Reasons:

  • Keeps templates clean and readable
  • Leverages SQL’s optimized JOIN capabilities
  • Allows easier filtering and sorting at the database level
  • Avoids extra lookups or nested loops in Jinja

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
✅ SQL JOINs (chosen) ✔️ Efficient
✔️ Simple templates
✔️ Filterable
❌ Requires more JOINs in queries
Template-level resolution ✔️ May look flexible at first ❌ Messy Jinja logic
❌ Slower/more complex

Authentication and Access Control

Decision 14: Use Flask-Login with Global Access Control via before_request

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We wanted users to stay logged in across visits without having to re-enter credentials each time, improving comfort and usability. We also needed to restrict access to sensitive routes (dashboard, payments, etc.) while keeping the codebase clean and manageable.

Decision

We used the Flask-Login package to handle authentication and session persistence via secure cookies. For route protection, we implemented a global before_request handler to check authentication status. Only specific endpoints (login, signup, static assets) are allowed without login. This avoids manually decorating every view with @login_required and ensures consistent access control.

Decision taken by: Caren Kedis, Denis Cercasin

Regarded options

| Option | Pros | Cons | |—-|—|—| | Manual @login_required decorators | ✔️ Fine-grained control
✔️ Explicit per route | ❌ Repetitive
❌ Risk of forgetting one | | ✅ Global before_request (chosen) | ✔️ Centralized control
✔️ Clean codebase
✔️ Always enforced | ❌ Slightly harder to debug route access |


Decision 05: MVP Scope – No Tenant-Facing Interface

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

In the early planning phase, we discussed whether the RentTracker MVP should include a tenant-facing interface — where tenants could log in, view their rental details, or mark rent as paid.

Implementing such a feature would require: -A separate user role system,

  • Additional routing and authentication logic,
  • Interface design for tenants,
  • And possibly different database access rules.

Given limited time and the focus of the project on tracking and reminding from the owner’s side, we had to evaluate the scope.

Decision

We decided not to include a tenant-side interface in the MVP. The app is built solely for landlords/owners.

Reasons:

  • The core problem we wanted to solve was owner-side tracking of rent status and reminders.
  • Most database and logic complexity lies on the owner side; tenant access would add marginal value for the first release.
  • This allowed us to focus on core functionality and ensure a usable, testable MVP.

Decision taken by: Caren Kedis, Denis Cercasin, in consultation with course professor

Regarded options

Option Pros Cons
Owner-side only (chosen) ✔️ Simpler scope ❌ No direct tenant interaction
Owner + Tenant roles ✔️ More realistic ❌ More complexity
Tenant-side only ❌ Not aligned with our core use case ❌ Owners need full data control

App Structure and Implementation Strategy

Decision 04: Use of Flask Blueprints for Modular Routing

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

The RentTracker application involves multiple modules with separate CRUD logic.

Without structure, all route handlers would reside in a single app.py or in a large routes.py, making the codebase difficult to navigate, extend, or test.

Although Flask Blueprints were not emphasized deeply in the course materials, we needed to evaluate whether using them would help us manage project complexity more effectively.

Decision

We decided to adopt Flask Blueprints to organize our routes by module.

Each core domain (e.g., tenants, apartments, auth) gets its own Blueprint file, grouped logically and registered with the app in app.py. This:

  • Keeps the code modular and easier to maintain,
  • Makes it easier to locate and isolate bugs,
  • Allows better separation of concerns as the app grows,
  • Allows to reuse code (e.g. same auth blueprint in multiple apps.)

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
All routes in one file ✔️ Simpler for very small apps ❌ Becomes unreadable and unscalable fast
Manually structured files (separate route files with no Blueprints) ✔️ Some logical grouping ❌ No Flask-native modularity, tricky app registration
Blueprints ✔️ Modular, scalable, recommended for larger apps ❌ Slight learning curve, extra initial setup

Decision 07: Partial Use of SQLAlchemy ORM

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We had to decide whether to use raw SQL or adopt SQLAlchemy as ORM for database interactions. SQLAlchemy was introduced only two weeks before the deadline, while most of our app already used plain SQL with SQLite.

Decision

We chose to stick with raw SQL for most of the app and experiment with SQLAlchemy only in the user model, where class-based structure was already needed for Flask-Login integration.

This approach allowed us to:

  • Avoid time-consuming refactoring late in the project,
  • -Still try out ORM concepts in one isolated case,
  • Maximize development time for core features.

Decision taken by: Denis Cercasin

Regarded options

Full ORM migration was too late-stage and risky. Sticking entirely to raw SQL would limit learning. This hybrid approach gave us both stability and exposure.

Table taken from our professor’s documentation: | Criterion | Plain SQL | SQLAlchemy | | — | — | — | | Know-how | ✔️ We know how to write SQL | ❌ We must learn ORM concept & SQLAlchemy | | Change DB schema | ❌ SQL scattered across code | ❔ Good: classes, bad: need Alembic on top | | Switch DB engine | ❌ Different SQL dialect | ✔️ Abstracts away DB engine |


Decision 03: Selective Use of WTForms and Bootstrap

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

WTForms and Bootstrap were introduced late in the semester, around three weeks before project submission. We had already developed most of the application using raw HTML forms and manual validation, following the teaching materials provided earlier.

Refactoring the entire UI and form logic to use WTForms and Bootstrap would have consumed time needed for implementing missing core functionality. However, these tools provide benefits like automatic validation and consistent styling, and we wanted to explore them for learning purposes.

Decision

We decided to partially adopt WTForms and Bootstrap in selected areas of the app, rather than refactoring all templates and forms.

Use cases include:

  • WTForms: used for authentication (login/signup) and for shared logic like deletion confirmation forms.
  • Bootstrap: used selectively to enhance styling in certain templates (e.g., dashboard) without rewriting all existing CSS.

This strategy allowed us to:

  • Focus on completing functional features,
  • Still experiment with modern tools,
  • Learn through practice while minimizing unnecessary refactor risks.

Decision taken by: Caren Kedis and Denis Cercasin

Regarded options

Option Pros Cons
Full refactor to WTForms + BS ✔️ Consistent, modern codebase ❌ Time intensive
No use of WTForms/BS ✔️ No additional workload, stick to known tools ❌ Missed opportunity to learn new things
Selective use ✔️ functional progress + exploration ❌ Inconsistent UI

File Storage and Sensitive Data

Decision 09: Include Secure Storage of Apartment and Tenant Documents

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to decide whether secure upload and storage of documents (e.g., tenant IDs, utility identifiers, scanned contracts) was a valuable and realistic feature for our MVP.

Our professor requested justification, given scope constraints.

Decision

We decided to include this feature based on real-world needs from Romanian and Moldovan rental contexts, where utility IDs and scanned documents are often scattered across unsecure channels.

Our app addresses:

  • Fragmented data (Excel, paper, chats),
  • Legal and organizational risks,
  • Need for centralized, structured access.

Decision taken by: Denis Cercasin, Caren Kedis

Regarded options

We considered skipping this for MVP scope reasons, but decided to include it due to its high practical value and positive feedback from potential users.


Decision 10: Store File Paths in Database, Not BLOBs

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

Having decided to support document uploads, we had to choose how to store the files: directly in the database as BLOBs, or as files on disk with paths stored in the DB.

Decision

We chose to store uploaded documents in the file system (e.g., uploads/) and save only the relative file path in the database.

Reasons:

  • Keeps DB size manageable and easier to back up
  • Better performance and debuggability
  • Easier to support larger files and multiple uploads
  • Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
BLOB in database ✔️ Everything in one place
✔️ Access control via Flask
❌ Slower performance
❌ DB grows fast
❌ Harder to debug
✅ File path (chosen) ✔️ Lightweight DB
✔️ Scalable
✔️ Easy to inspect and back up
❌ Needs file management
❌ Slightly more setup

Notifications and Communications

Decision 17: Use Telegram for Rent Reminders

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to choose a channel for sending rent reminder notifications to property owners. Options included email, Telegram, Viber, and WhatsApp.

Our goals were:

  • Fast setup and easy testing,
  • Real-time, mobile-friendly notifications,
  • A chance to explore external API integration in practice.

Decision

We chose to implement reminders using a Telegram bot, integrated with the Telegram Bot API.

Reasons:

  • Easy to register and control bots via Telegram Bot API.
  • No manual pairing required.
  • Fun and practical opportunity to work with real-world APIs.
  • Telegram is widely adopted among our target users, especially in Eastern Europe.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
✅ Telegram ✔️ Easy bot setup
✔️ Real-time
✔️ Fun API project
❌ Requires user to have Telegram
Viber ✔️ Popular in some regions ❌ Bot setup complex
❌ Limited docs/support
WhatsApp ✔️ Popular globally ❌ Business-only API
❌ Not free/easy to test bots
Email ✔️ Universal
✔️ Familiar UX
❌ Less engaging
❌ Not real-time
❌ Boring 😉

Decision 18: Telegram Reminder Workflow via API + Autonomous Bot

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We wanted to implement Telegram-based rent reminders without manually collecting users’ chat IDs. The system should be easy to use, secure, and support fully autonomous, scheduled reminder sending in the future.

Our professor also required us to include an API in our project - this presented a chance to design a clean interface between the Flask app and the Telegram bot.

Decision

We designed a two-part integration between the Flask app and Telegram:

  1. User Chat ID Linking
    • Users click a “Connect Telegram” button in the UI.
    • They are redirected to our Telegram bot (t.me/OurBotName).
    • On /start, the bot reads the user’s chat_id and passes it back to the Flask app, linked via a one-time token.
    • The app stores this chat_id in the users table.
  2. Reminder Execution
    • The bot runs as a scheduled script, hosted via GitHub Actions.
    • It calls a Flask API endpoint (e.g., /api/reminders/today) to fetch a list of users who should receive reminders.
    • Then it sends messages using the Telegram Bot API.

This clean separation allows independent scaling and easy testing. It also fulfills the API requirement without adding unnecessary frontend complexity.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Manual entry of chat_id ✔️ Simple ❌ Bad UX
❌ Error-prone
✅ Auto-link via Telegram + token (chosen) ✔️ Seamless UX
✔️ Secure
✔️ No manual steps
❌ Needs some bot-side logic
Bot queries DB directly ✔️ Direct access ❌ Tightly coupled
❌ Harder to scale
✅ Bot calls Flask API (chosen) ✔️ Clean separation
✔️ Reusable
✔️ Matches project API goal
❌ Needs endpoint & auth

Note on polling vs. webhook: For simplicity, we use polling in the development phase. Webhooks may be added later for real-time responsiveness and hosting efficiency.


Decision 19: Support Per-User Custom Reminder Day

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

The initial reminder logic was static: all users would receive Telegram notifications on a hardcoded day each month (e.g., the 28th). This approach lacked flexibility and didn’t reflect how landlords manage rent collection in real life.

To make reminders more useful and personal, we needed to let each user choose which day of the month they want to receive reminders.

Decision

We extended the reminder system to allow per-user reminder day selection, stored in the database (e.g., reminder_day column in the users table).

Each day, the scheduled bot script:

  • Checks the current day (e.g., 31),
  • Queries all users with reminder_enabled = 1 and reminder_day = 31,
  • Sends reminders only to those matching users.

This makes reminders personal, aligns with the app’s real-world use case, and enhances user value.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Hardcoded day (e.g. 28th) ✔️ Simple to implement ❌ No personalization
❌ Less useful
✅ User-defined day (chosen) ✔️ Realistic
✔️ User-friendly
✔️ Easy to extend
❌ Slightly more DB/query logic

Related Decision: See Decision 18 for how the Telegram bot fetches reminders via the API.


Decision 20: Use SendGrid for Email Delivery Instead of Flask-Mail or SMTP

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to send confirmation/reset emails from our Flask app. Initial attempts using Flask-Mail, direct SMTP, and Gmail failed due to:

  • Blocked ports on our development machines,
  • Gmail rejecting test emails due to security checks,
  • Flaky and slow delivery, especially during testing.

SMS was considered, but requires phone verification and external APIs, which added complexity and costs.

Decision

We switched to SendGrid for email delivery, based on our professor’s recommendation and its easy Flask integration via API.

We also used the itsdangerous package to generate secure, time-limited tokens for reset links and email confirmations.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Flask-Mail + SMTP ✔️ Simple setup in theory ❌ Blocked ports
❌ Gmail restrictions
Gmail via API ✔️ Familiar ❌ Setup overhead
❌ Spam/virus checks
SMS ✔️ Fast, mobile-first ❌ Costly
❌ Complex
❌ Needs verified numbers
✅ SendGrid (chosen) ✔️ Works behind firewalls
✔️ API-based
✔️ OK free tier
❌ Slight delay to some inboxes
❌ 60-day trial

Decision 15: Host Reminder Bot as Standalone Script via GitHub Actions

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

The rent reminder bot (bot_send_reminders.py) runs independently of the Flask app. It checks daily who should be notified and sends messages via Telegram.

We needed to decide where and how to host and trigger this script regularly, ideally without adding infrastructure complexity.

Decision

We decided to run the bot as a standalone Python script, triggered once daily using GitHub Actions with cron.

Reasons:

  • Simple to set up
  • Runs separately from Flask, avoiding blocking or session issues
  • Free tier covers our needs during development and testing
  • Can be moved to cron or cloud scheduler later if needed

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Celery + Redis ✔️ Scalable
✔️ Industry standard
❌ Complex setup
❌ Overkill for now
APScheduler in Flask ✔️ Easy to use ❌ Tied to app runtime
❌ Not reliable in prod
System Cron (Linux) ✔️ Simple, effective ❌ Requires server setup
GitHub Actions + cron (chosen) ✔️ Fast to deploy
✔️ Free
✔️ Portable
❌ Limited logging/debugging

Decision 16: Use Python 3.11 for Compatibility with python-telegram-bot v20+

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We initially set up our project using Python 3.13.1, the latest version available. While Flask and most of our libraries worked fine, we encountered compatibility issues with the python-telegram-bot package (v20+), which is core to our reminder system.

This package does not yet support Python 3.13+ — installation fails or runtime errors occur due to missing or deprecated internals.

Decision

We downgraded the project’s virtual environment to Python 3.11.0, which is officially supported by python-telegram-bot v20+.

This ensured:

  • Stable operation of the Telegram bot,
  • Full compatibility with async features,
  • A common version also supported by GitHub Actions and hosting environments.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Python 3.13.1 ✔️ Latest features
✔️ Default on some new systems
❌ Telegram bot fails to install/run
Python 3.11.0 (chosen) ✔️ Fully compatible with python-telegram-bot v20+
✔️ Stable
❌ Slightly older, but no practical downsides

UX and Feature Design

Decision 26: Implement Dashboard as a Cash Flow Projection Tool

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We initially considered the dashboard as a simple home screen with basic navigation. However, our professor suggested a more meaningful use: a cash flow projection to help landlords understand both current and upcoming rental income.

The idea was to avoid short-term optimism when tenants pay in advance, and instead track when future payments will actually be due.

Decision

We redesigned the dashboard to focus on cash flow awareness, including:

  • Number of owned apartments
  • Number of active rental agreements
  • Overview of months that are:
    • Already paid in advance
    • Still unpaid
  • Highlight of upcoming payment deadlines

This adds practical value, improves financial planning, and helps users avoid liquidity gaps.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Navigation only ✔️ Easy to build ❌ Low value
❌ No financial insights
✅ Cash flow projection (chosen) ✔️ Real-world helpful
✔️ Better UX
❌ Requires more dynamic data logic

Decision 11: Add Filtering to Rent Payments View

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

The rent payments view initially displayed a full table of all payments across all tenants, apartments, and months. As the dataset grows, this becomes overwhelming and difficult to use, especially for users managing multiple properties.

Decision

We introduced filtering options for the rent payments view:

  • By apartment
  • By tenant
  • By month

This improves clarity, supports scalability, and aligns with real-world workflows.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
Full table only (no filters) ✔️ Simple to implement
✔️ Shows complete history
❌ Hard to navigate
❌ Not scalable
✅ Add filters (chosen) ✔️ Scalable
✔️ Better UX
✔️ Aligns with workflows
❌ More implementation effort

Decision 13: Use GET Method for Rent Payment Filtering

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

We needed to implement filtering for the rent payments list. The question was whether to submit the filter form using GET or POST - redirecting therefore to a new route.

Decision

We used the GET method for filter submissions.

Reasons:

  • Filtering doesn’t change data — it’s a read operation.
  • GET parameters appear in the URL, making filtered views bookmarkable and shareable.
  • Aligns with REST principles and improves caching behavior.

Decision taken by: Denis Cercasin

Regarded options

Option Pros Cons
POST ✔️ Form data stays hidden ❌ Not RESTful
❌ No URLs/bookmarks
✅ GET (chosen) ✔️ Bookmarkable
✔️ Semantic
✔️ Works with back button
❌ Query string may get long

Project Meta and Documentation

Decision 06: Use of Provided Documentation Template

Meta

Status
Work in progress - Decided - Obsolete

Updated: 21-06-2025

Problem statement

To document the development process of the RentTracker project, we needed a structured, consistent format that would allow us to explain decisions, architecture, and functionality.

With limited time and a large development workload, our goal was to use a simple, working solution that still looked clean and professional.

Decision

We chose to use the documentation template provided and recommended by our professor, which is hosted via GitHub Pages and uses the Just the Docs theme (a Jekyll-based static site generator).

This decision allowed us to:

  • Quickly publish and structure the documentation without building it from scratch,
  • Focus on content rather than layout or tooling,
  • Ensure compatibility with evaluation criteria,
  • Maintain a clear, navigable structure for decision logs, architecture notes, and user documentation.

The template was already known to us from course materials and easy to adapt to our specific needs.

Decision taken by: Caren Kedis, Denis Cercasin

Regarded options

We briefly considered building our own documentation site using tools like Sphinx, Docsify, or Docusaurus. While those would offer more control and features, they also introduced a steeper learning curve and higher setup effort. Plain Markdown files in the repo were another option, but they lacked navigation and structure.