INTRODUCTION:

The Hostel Complaints System is a Python program, designed to manage student complaints in a hostel environment. This system employs a file-based database approach, utilizing text files for data persistence instead of a traditional database management system. This design choice makes it lightweight, portable, and accessible for educational purposes while demonstrating fundamental programming concepts.


The application follows a modular architecture with clear separation of concerns: file management, complaint processing, user interaction, and administrative functions.Below I have explained each component in detail to teach you the complete implementation.



FILE SYSTEM INFRASTRUCTURE.


A) DIRECTORY STRUCTURE CREATION:


import os

# Get the directory where this script is located

script_dir = os.path.dirname(os.path.abspath(__file__))

# Create a Data folder inside the script directory

data_dir = os.path.join(script_dir, "Data")

# Create a complaints folder inside the Data folder

complaints_dir = os.path.join(data_dir, "complaints")

# Create the folders if they don't exist

os.makedirs(complaints_dir, exist_ok=True)


Explanation:

The file system setup begins with importing Python's os module, which provides a portable way of interacting with the operating system. The __file__ special variable contains the pathname of the current script file. Using os.path.abspath(__file__) converts a potentially relative path to an absolute path, ensuring consistency regardless of how the script is executed.


The os.path.dirname() function extracts the directory portion from a full pathname. For example, if __file__ is /home/user/project/script.py, then os.path.dirname(os.path.abspath(__file__)) returns /home/user/project.


The os.path.join() function constructs pathnames in an operating system-independent manner. On Windows, it uses backslashes (\), on Unix-based systems, it uses forward slashes (/). This avoids hardcoding path separators, making the code portable across different platforms.


The os.makedirs() function creates directories recursively. The exist_ok=True parameter is crucial, it prevents the function from raising an exception if the directories already exist, making the code idempotent (safe to run multiple times without errors).


B) FILE PATH CONFIGURATION:

serial_file = os.path.join(data_dir, "serial_counter.txt")

index_file = os.path.join(data_dir, "complaint_index.txt")

resolved_file = os.path.join(data_dir, "resolved_complaints.txt")


Explanation:

The system maintains three critical text files for its operation:

1. serial_counter.txt: This file stores a single integer value representing the last used complaint ID. It acts as a counter to ensure each complaint receives a unique identifier. The counter starts at 0 and increments with each new complaint.

2. complaint_index.txt: This file serves as a master index of all active (unresolved) complaints. Each line follows a structured format: serial_number | name | room_number | category. This denormalized approach allows quick browsing of complaints without opening individual files.

3. resolved_complaints.txt: This archive file maintains a historical record of resolved complaints using the same format as the index file. This separation between active and resolved complaints simplifies management and reporting.


C) FILE INITIALIZATION:

if not os.path.exists(serial_file):

    with open(serial_file, "w") as f:

        f.write("0")

if not os.path.exists(index_file):

    open(index_file, "a").close()

if not os.path.exists(resolved_file):

    open(resolved_file, "a").close()


Analysis:

The initialization process ensures the application can start from a clean state without pre-existing files. The os.path.exists() function checks for file existence before attempting operations.

For serial_counter.txt, if it doesn't exist, the code creates it with a write operation ("w" mode) and initializes it with "0". The with statement context manager guarantees proper file closure even if errors occur during writing.

For the index and resolved files, the code uses open(file, "a").close(). The append mode ("a") creates the file if it doesn't exist but doesn't truncate it if it does. Immediately closing the file ensures it's properly created without writing any content. This approach is more efficient than writing an empty string.



CORE FUNCTIONALITY IMPLEMENTATION.


A) SERIAL NUMBER MANAGEMENT.


def get_next_serial():

    with open(serial_file, "r+") as f:

        serial = int(f.read()) + 1

        f.seek(0)

        f.write(str(serial))

    return serial


Explanation:

The get_next_serial() function implements a critical atomic operation for generating unique identifiers. Let's examine it step by step:

1. File Opening: The function opens serial_counter.txt in "r+" mode, allowing both reading and writing. The file pointer starts at position 0 (beginning of file).

2. Reading Current Value: f.read() reads the entire file content. Since the file contains only a number, this returns a string representation of the current serial number.

3. Value Conversion and Increment: int(f.read()) converts the string to an integer, and adding 1 generates the next serial number.

4. Pointer Repositioning: f.seek(0) moves the file pointer back to the beginning of the file. This is essential because after reading, the pointer is at the end of the file, and writing would append rather than overwrite.

5. Writing New Value: f.write(str(serial)) converts the integer back to a string and writes it to the file, replacing the previous value.

6. Return and Cleanup: The function returns the new serial number, and the with statement automatically closes the file, ensuring no resource leaks.



B) FILE APPENDING UTILITY FUNCTION.


def file_append(filename, text):

    with open(filename, "a") as f:

        f.write(text + "\n")


Explanation:

This helper function demonstrates the principle of DRY (Don't Repeat Yourself) by encapsulating the file appending logic. The append mode ("a") ensures that:


1. The file is created if it doesn't exist

2. New content is added to the end without affecting existing content

3. The file pointer is positioned at the end for writing


Adding "\n" (newline character) ensures each entry appears on its own line, maintaining proper file formatting across different operating systems (though Python handles line ending conversions transparently in text mode).



COMPLAINT SUBMISSION PROCESS.


A) USER INFORMATION COLLECTION.


name = input("Enter your name: ")

room = input("Enter your room number: ")


Comprehensive Analysis:

The input() function displays a prompt and waits for user input. The entered text is returned as a string. This simple approach works well for console-based applications but lacks validation. In a production system, you would add:

  • Input validation (e.g., checking for empty strings)
  • Sanitization to prevent injection attacks (though less critical for file-based systems)
  • Format requirements (e.g., room number patterns)


B) CATEGORY SELECTION MECHANISM.


categories = [

    "Food Issues", "Water Supply", "Electricity Problems", 

    "Internet Issues", "Room Maintenance", "Other Complaints"

]


print("\nComplaint Categories:")

for i, cat in enumerate(categories, 1):

    print(f"{i}. {cat}")


cat_choice = int(input("Select a category: "))

category = categories[cat_choice - 1]


Explanation:

The category system uses a list data structure for ordered storage of complaint types. The enumerate() function with a start value of 1 (enumerate(categories, 1)) creates numbered options for user selection.

The conversion int(input(...)) is potentially risky, if the user enters non-numeric text, it will raise a ValueError. A robust implementation would include error handling with try-except blocks.

The index adjustment (cat_choice - 1) converts from 1-based (user perspective) to 0-based (programming perspective) indexing. This is a common pattern in menu systems.



C) SUBCATEGORY SELECTION SYSTEM


subcategories = {

    "Food Issues": ["Food Quality", "Meal Timings", "Canteen Staff Behavior", "Other"],

    "Water Supply": ["Drinking Water Problems", "Wash Water Issues", "Other"],

    "Electricity Problems": ["Power Outages", "Voltage Issues", "Other"],

    "Internet Issues": ["No Internet Access", "Slow Internet Speed", "Other"],

    "Room Maintenance": ["Room Cleaning Required", "Bathroom Not Cleaned", "Broken Items", "Other"],

    "Other Complaints": ["User Defined"]

}


Explanation:

The subcategory system uses a dictionary where keys are main categories and values are lists of subcategories. This hierarchical organization:

1. Groups related subcategories under appropriate main categories

2. Allows dynamic retrieval based on user's main category selection

3. Provides a structured yet flexible taxonomy for complaints

The inclusion of "Other" and "User Defined" options demonstrates thoughtful design for handling edge cases and unexpected complaint types.


if subcategory == "Other" or subcategory == "User Defined":

    subcategory = input("Enter your complaint subcategory: ")


This conditional logic enables flexibility, when predefined options don't fit, users can specify their own subcategory. This approach balances structure with adaptability.



D) COMPLAINT DETAILS AND STORAGE


details = input("\nEnter details about your complaint: ")


serial = get_next_serial()

filename = os.path.join(complaints_dir, f"complaint_{serial}.txt")


with open(filename, "w") as f:

    f.write(f"Complaint No: {serial}\n")

    f.write(f"Name: {name}\n")

    f.write(f"Room: {room}\n")

    f.write(f"Main Category: {category}\n")

    f.write(f"Sub Category: {subcategory}\n")

    f.write(f"Complaint: {details}\n")


file_append(index_file, f"{serial} | {name} | Room {room} | {category}")


Explanation of Strategy:

The system employs a dual storage approach:

1. Detailed individual files: Each complaint gets its own file with a name pattern complaint_{serial}.txt containing all relevant information in a structured format.

2. Index file: A centralized index contains summary information for quick reference without opening individual files.


This design offers several advantages:

  • Fast browsing through the index file
  • Detailed information available when needed
  • Isolation between complaints (one corrupted file doesn't affect others)
  • Simple backup and management of individual complaints


The use of f-strings (formatted string literals) creates readable output with variable interpolation. The consistent formatting with labels (Name:, Room:, etc.) makes the files human-readable and easily parsable.



ADMINISTRATIVE FUNCTIONS


A) AUTHENTICATION SYSTEM


def admin_login():

    password = input("Enter admin password: ")

    return password == "admin123"


Security Analysis:

This implementation uses a hardcoded password comparison, which is simple but insecure for several reasons:

1. The password is visible in the source code

2. No encryption or hashing protects the password

3. No account lockout after failed attempts

4. Single shared credential without individual accounts


In a production system, you would:

  • Store password hashes instead of plain text
  • Use a dedicated authentication system
  • Implement account lockout after multiple failures
  • Support multiple administrators with individual credentials


B) COMPLAINT VIEWING INTERFACE


def view_complaints():

    with open(index_file, "r") as f:

        lines = f.readlines()

        if not lines:

            print("\nNo unresolved complaints.")

            return


File Reading Technique:

The readlines() method reads all lines into a list, with each line as a separate element. Checking if not lines determines if the list is empty, indicating no unresolved complaints.


    print("\nCurrent Complaints:")

    for line in lines:

        print(line.strip())


The strip() method removes leading and trailing whitespace, including the newline character added during file writing. This ensures clean output without extra blank lines.


    serial = input("\nEnter serial number to view details or press Enter to return: ")

    if serial.strip():

        file = os.path.join(complaints_dir, f"complaint_{serial}.txt")

        if os.path.exists(file):

            with open(file, "r") as comp:

                print("\nComplaint Details:")

                print(comp.read())


Robust File Handling:

The code checks if serial.strip() to verify the user entered something other than whitespace. Then it constructs the expected filename and verifies its existence with os.path.exists() before attempting to read it. This defensive programming prevents errors from invalid serial numbers.


            resolve = input("Mark as resolved? (Y/N): ")

            if resolve.lower() == 'y':

                resolve_complaint(serial)


The .lower() method converts the response to lowercase, making the check case-insensitive (accepting 'Y', 'y', 'N', 'n').



C) COMPLAINT RESOLUTION PROCESS


def resolve_complaint(serial):

    with open(index_file, "r") as f:

        lines = f.readlines()


    new_lines = []

    resolved_line = ""

    for line in lines:

        if line.startswith(f"{serial} "):

            resolved_line = line

        else:

            new_lines.append(line)


    with open(index_file, "w") as f:

        f.writelines(new_lines)


    file_append(resolved_file, resolved_line.strip())


Algorithmic Explanation:

This function implements a filter-and-replace operation on the index file:

1. Read all lines from the index file into memory

2. Iterate through each line, checking if it starts with the target serial number

3. Separate the target line (to be moved to resolved) from other lines (to keep in index)

4. Write the remaining lines back to the index file, effectively removing the resolved complaint

5. Append the resolved complaint to the resolved complaints file


The use of startswith(f"{serial} ") (with a space after the serial number) prevents partial matches (e.g., serial "1" matching "10", "11", etc.).

The writelines() method writes a list of strings to the file efficiently. Unlike write(), it doesn't add any separators between the lines, so the original newline characters preserved in the list elements maintain proper formatting.



USER INTERFACE FLOW


A) ADMINISTRATIVE PANEL DESIGN


def admin_panel():

    if not admin_login():

        print("Incorrect password!")

        return


    while True:

        print("\nAdmin Panel:")

        print("1. View Current Complaints")

        print("2. View Resolved Complaints")

        print("3. Logout")

        choice = input("Select an option: ")


User Experience Considerations:

The admin panel uses an infinite loop (while True) to maintain the menu until explicitly exited. This pattern is common in console applications where users need to perform multiple operations in a session.

The clear menu numbering and consistent formatting enhance usability. The logout option (breaking the loop) provides a clear exit path.



B) MAIN APPLICATION LOOP


def main():

    while True:

        print("\n============================")

        print("| HOSTEL COMPLAINTS SYSTEM |")

        print("============================")

        print("1. Submit Complaint")

        print("2. Admin Login")

        print("3. Exit")

        choice = input("Choose an option: ")


Architectural Pattern:

The main function implements the application controller pattern, directing flow based on user choices. The banner decoration with equals signs and vertical bars creates visual separation, making the interface more appealing.

The while loop continues until the user explicitly chooses to exit, providing a continuous service rather than a one-time execution.



OTHER IMPORTANT THINGS


A) EXECUTION MAP

└─ main()

     ├─ submit_complaint()

     │     ├─ ask name, room

     │     ├─ show categories → pick one

     │     ├─ show subcategories → pick one / enter custom

     │     ├─ enter complaint details

     │     ├─ get_next_serial()

     │     │     └─ read/write serial_counter.txt

     │     ├─ write complaint_<serial>.txt in /complaints/

     │     ├─ append complaint info to complaint_index.txt

     │     └─ print "submitted successfully"

      

     ├─ admin_panel()

     │     ├─ admin_login()

     │     │     └─ check password == "admin123"

     │     └─ loop:

     │           ├─ view_complaints()

     │           │     ├─ read complaint_index.txt

     │           │     ├─ list unresolved complaints

     │           │     ├─ open complaint_<serial>.txt for details

     │           │     └─ option to resolve → resolve_complaint()

     │           │           ├─ remove line from complaint_index.txt

     │           │           ├─ append to resolved_complaints.txt

     │           │           └─ print "marked as resolved"

     │           ├─ view_resolved()

     │           │     ├─ read resolved_complaints.txt

     │           │     └─ display resolved list

     │           └─ logout (break loop)

     └─ Exit



B) EDUCATIONAL VALUE FOR BEGINNERS.


This project exemplifies several important programming concepts:

File I/O Operations: Reading, writing, and appending to files with proper resource management.

Data Structures: Effective use of lists, dictionaries, and strings for data organization.

Control Flow: Implementation of menus with loops and conditional branching.

Modular Programming: Separation of functionality into discrete, reusable functions.

User Interface Design: Creating intuitive console-based interfaces.

Data Persistence: Strategies for maintaining state between application runs.

Input Processing: Handling and validating user input.

String Manipulation: Formatting and parsing text data.


By studying this implementation, beginners gain exposure to practical application development with immediate visual feedback, making abstract programming concepts more concrete and understandable.

The system's simplicity allows for gradual enhancement, providing a foundation upon which more complex features can be built as programming skills advance.



C) IMPORTANT SCREENSHOTS:


Main Menu + Categories:




Subcategories + complaint filing:




Admin panel + Current Complaints:



Single Complaint Detailed View:



Resolved Complaints:




D) SOURCE CODE:


🔗 GitHub Repo



E) CLOSING NOTE:

Unlike my first project with strict guidelines, this one gave me free rein. The idea came from our hostel's messy physical complaint register, just a simple notebook with no organization. I thought, "Why not make this a proper program?"


I started with an execution map on a page, improving it again and again as I added parts to overcome limitations. When I began coding, if I couldn't implement something complex, I changed it into a simpler solution that still worked. I built it step-by-step, using basic tools like lists and text files, until it became a complete system. It taught me that starting with a clear, personal idea and adapting as you go is what turns a concept into a real working program.