Developer: Felix Lehmann
Render.com App: Link
Github: Link
This project simulates a music center, called Schallplatte, which rents 9 rehearsal rooms to its members/musicians. It seeks to create and maintain a community for musicians, that's why an online forum has been announced for the near future. As hinted in the milestones (the about page), an own rock event/festival is planned. By now, the modern and minimalistic design of this website shall attract for young people. So, this project is solely done in a mobile-first principle. Moreover, an upcoming forum on this website is announced, which shows the vitality of this builing. For explanation: "Schallplatte" is the German word for a vinyl.
The challenges in this project mostly appeared when working with the MVS/MVT. Django is a very powerful framework but I quite often didn't fully understand what I was doing. So, studying the MVT framework itself became the most time consuming part in the project. Eventually, I mastered extending the user model, as username and email was not enough for a music center that clearly wants to set up a social network. In contrast, building the object model for the calendar cursor was a great challenge.
Currently existing user account with multiple bookings
- U: w.heisenberg P: quantum1925
- U: e.schroedinger P: cats1935
Currently, these days have the most booked items:
- 02/08/2025
- 06/08/2025
- 30/08/2025
Feel free to register and try it out
- Site Owner Goals
- Target group
- Design
- Technologies used
- Structure
- Features
- Testing
- Bugs
- Heroku deployment
- Credits
- Acknowledgments
The main goal is to attract as many site musicians as possible and convince them to rent the rehearsal rooms. For that, which can be seen as the second main goal, the visitors must register and become part of Schallplatte's community.
What is a typical musician Well, that is not at all easy to answer, but there are some points that can be narrowed down. Nearly all musicians, practitioners and composers want a room practice. When they are in their creative phase, they don't want to be disturbed. Also, the life of a creative mind can quickly become spontaneous. Finall, they look for other artists they can share ideas with or simply enjoy their passion.
- what if there would be a music center where members can book rehearsal rooms
- different rooms for different purposes to build up a community
- large rooms/medium rooms/small rooms
- for singers, bands, practicers, performers, professionals
- big band rooms with drums, several amps and synths
- medium rooms for hobby bands or professionals to practice their gigs
- small rooms for practicioners, single musicians, creative environments, projects etc
After these thoughts, the profile becomes clear. A music center that tackles the above issues, definitely benefits from a website that raises attention for this community.
Info: there is not intention of the order of the user stories As a first/general user
- As a first user I can visit a forum page so that I can get information about the latest news
- As a user I can switch between dark theme and light theme so that I can visit the page with more comfort
- As a first user I can register so that I'll be able to book rehearsal rooms
- As a first user I can see a brief presentation about the center on an about page so that I know with whom I am dealing with
- As a first user I can see pictures of the rehearsal rooms so that I can decide which room fits the best for my purpose
- As a first user I can visit the landing page so that I get to know what the music center "Schallplatte" is about
As a member
- As a member I can log in so that I can book rehearsal rooms
- As a member I can successfully book a rehearsal room so that I can enter it an practice music
- As a member I can modify existing bookings so that it fits into my personal time schedule.
- As a member I can cancel bookings so that I can free up time slots for others.
- As a member I can choose time slots in a calendar view so that so that I can see if rooms are available before I actually request the booking.
- As a member I can filter rooms in the booking process by size and containing instrument so that I can find suitable rooms more efficiently
- As a member I can log out from my profile so that others can't enter it (accidentally)
- As a member I can view/edit my profile so that I have full control about my own data
- As a member I can view/receive permanent notifications in my personal account to view the booking history.
Before we go into the details of the design, I want to highlight some project related principles about design. We target young creative artists, meaning that the website is mostly seen in a mobile view. As a consequence, all features should be designed with the mobile first approach, even if it is time consuming, especially features like a calendar tool were the user needs to see other booking items, too.
Second, quick JS solutions for styles and designs/themes seems to be tempting. However, the maintanance in future becomes more difficult. So, the principle for this project is "No JS is better than good JS". Sooner or later, you will use JavaScript anyway for tricky and complicated cases - it will be difficult enough to maintain. The rest, that can be done outside of JS, should be done outside of it. In particular, using proper CSS selectors, using classes in html-tag as well as custom "data-[...]"-attributes.
These two principles from above significantly improves User experience and stability. No cracking while scrolling, less risks of bugs etc.
The page design can be put into 3 main categories.
core pages (like landing page, about, rooms presentation and forum announcement). Typical: hero sections, simplistic and centralized design.
calendar tool for booking rooms. It's a one page "application" that fits all necessary features on one screen.
Regarding the color paletts: I have two paletts. One for a dark theme, one for a light theme. One might wonder why I put effort into this. There are two reasons:
- Global Custom Color variables in CSS it creates the need to declare the theme in the CSS selectors which allows me to completely ignore JS. The advantage: I can now, based on the theme (which is an attribute in the html), automatically choose between custom colors, if I create global root-variables in CSS (i saved the global color variables in a separate "themes.css"). I only need to import that CSS file to other css and i have the same colors everywhere
- Use of "theme" attribute in the html to customize Bootstrap one might question this as a benefit, since it is quite some work to set up. Well, these special CSS selectors make the selections of higher priority than without. As an example:
html[theme="dark"] mainwill overwritemain. Well, this is a great feature, because it means I can easily customize all bootstrap classes from now on. I don't have to go into the Bootstrap classes and adjust them there and I don't have to accept the re-occuring look of Bootstrap but I still benefit from the efficiency of developing features and components (like collapsing nav bars, drawers, proper models etc.). And all that without the use of JS and!important
- html
- CSS
- Django/python
- postgresql
- Heroku
- Bootstrap 5.3
- Fontawesome 5
- GitHub (Projects, Kanban, Milestones)
- Git
- Visual Studio Code
- Google Chrome dev tools
- Greenshot
- Balsamiq
- Since this project is a full stack project within the Django framework, the page structure orientates stongly to the app structure:
- app: main
- landing page (index.html)
- about.html
- forum.html
- rooms.html (this has not much to do with the app rooms, this page's purpose is to explain what rooms there are)
- app: user
- login.html (belongs to allAuth)
- signup.html (belongs to allAuth)
- profile.html
- prodile_edit.html
- notifications
- app: rooms
- calendar.html
- admin
- allAuth
- app: main
Seeing this structure, it is obvious that I extended allAuth's standard user model. In the next chapter (Data Models), I'll explain more details. It is also been said, that I did not finish the notification.html as well as the filter section in calendar.html. But the main functionalities are all working (adding, cancelling bookings etc.).
Regarding the Models, there are two main models:
extended user model. once for profile data which can be edited on the user's profile page and notifications (unfinished)
Rooms model. Each of the 9 rooms is saved with size, instruments and name. Then, the calendar model. here are all booked items of a room by a user saved. Data validation is done by the interactive calendar tool.
Personally, this was the part with the most fun (apart from designing and creating the calendar view). The calendar cursor object is saved in the rooms/services.py file. The idea came from sql cursors that I have seen in Java and python. The concept of a current calendar-day position (in combination with it as an object) is quite useful in this app.
-
collapsing nav bar in mobile mode
-
logged in profile button in nav bar
-
calender interface -> mark multiple slots
-
mobile view of the booking tool (moving filters to a drawer, moving confirmation sectoin to the bottom slide view)
-
deleting booked items
-
auto-fade confirmations
- html was tested by viewing the source code in the deployed website on render
- open the page - right click - view page source
- copy/paste into the W3C-validator https://validator.w3.org/#validate_by_input
- tested again after amendments: calendar.html, index.html, profile.html
Important:
- while checking the calendar.js, JSHint is no longer up to date -> I switched to ESLint.
- What I did: for the variables
document,windowandbootstrap, I declared them as global as you can see in the screenshots. Since they are no fails. JS knows these variables well. - tested again after amendments: calendar.js, calendar-ux.js, calendar-utils.js
- flake8 has been used to validate
SEE DETAILS
PROJECT: settings.py:
- "line too long" can't be shortened
- "env unused" necessary for render.com
PROJECT: urls.py: No errors
APP MAIN: No errors
APP ROOMS:
- unused variables are necessary for the testing (not the variables but the effect)
APP USER:
- signals is necessary
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Forum page | Visit /forum/ |
Forum loads with latest news or discussions visible | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Theme Switcher | Toggle theme via icon or UI switch element | Page changes theme between dark and light instantly | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Registration | Fill out and submit the registration form | User account is created, redirected and confirmed by a toast | Works as expected |
I can see a brief presentation about the center on an about page so that I know with whom I am dealing with
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| About Page | Visit /about/ |
Clear and informative description of the center is displayed | Works as expected |
I can see pictures of the rehearsal rooms so that I can decide which room fits the best for my purpose
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Room Gallery | Navigate to/Visit /rooms/ |
Pictures of all rehearsal rooms are visible and informative | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Landing Page | Visit / |
Intro section explains the purpose and vibe of "Schallplatte" | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Login | Submit login form when visiting / |
User is authenticated and redirected to the personal profile + success toast is shown | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Booking System | visit /rooms/calendar/ by clicking on "book" in the profile page or rooms-page: Select time slot and submit booking |
Booking is saved and visible in the profile page + success toast is shown | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Booking System | visit /rooms/calendar/ by clicking on "book" in the profile page or rooms-page: Select time slot and submit booking |
Booking is saved and visible in the profile page + success toast is shown | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Booking Management | Cancel an existing booking on the profile page | Booking is removed and time slot becomes available | Works as expected |
I can choose time slots in a calendar view so that I can see if rooms are available before I actually request the booking
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Calendar View | Open calendar and hover/select slots | Availability of rehearsal rooms is clearly visible and selectable | Works as expected |
I can filter rooms by containing instruments and room size so that I can find suitable rooms efficiently
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Room Filter | Use size/instrument filters before booking | Only matching rooms are shown; booking becomes faster and more convenient | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Logout | Click logout button | Session ends, user is redirected and protected + success toast | Works as expected |
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Profile Page | Visit and edit profile fields | Personal data is displayed and can be updated successfully by using a toggle button | Works as expected |
I can view/receive permanent notifications in my personal account so that I can view the booking history.
| Feature | Action | Expected Result | Actual Result |
|---|---|---|---|
| Booking Notifications | Open profile or dashboard area | Past bookings are listed or visible via permanent notification/messages | Not Done Yet |
What was tested:
Room.__str__()returns the correct string format ("{id}: {name}")RoomCalendar.__str__()outputs expected booking details including user and time range- Deleting a
Roomalso removes related entries in ``RoomCalendar (cascade delete) - Focus on string representation and **relational an relational integrity
test_get_cell_key()simply tests if the correct cell key is being generated (pure calculation, no mock)test_cell_keys_for_booking()tests for both relevant half-hour keys to verify correct mapping of booking time ranges (calculation based on a real booking instance)test_user_and_all_cell_keys(): testuser_cell_keysvs.all_cell_keys: to check that only the current user's keys are filtered correctly (functionality, real DB entries)test_save_booking_successcreates a new booking if the slot is free (testing standard behavior)test_save_booking_conflict_raisesraisesValueErrorwhen bookings overlap. It tests that conflicts are being detected.
test_calendar_view_authenticate()checks that a logged-in user receives a valid response and context from the calendar view.- functional test with real user login: Ensures that templates, forms and data objects are rendered correctly
test_booking_success()verifies that a booking can be created through the view when all data is valid.- confirms successful DB entry and message
test_booking_invalid()simply verifies if the function returns an error message on invalid input data ("start:": "","end": "","room": "")
collapseNavBar()basically tests 3 scenarios:- collapse the navbar when
window.innerWidth <= 768(tested viaCalls .hide()to confirm correct conditional logic) - don't collapse the navbar when
window.innerWidth > 768and - don't misbehave when the DOM element is missing
- calendar.js was too complex to be tested by JEST, so, I excluded UX and UTILS and created 3 js-files
- also the continuous testing of these 3 files is crucial when doing further developments
- for that, also the most basic functions are tested for their outcome
What was tested:
highlightCell()adds the classselected-slotto verify if the cell marking was applied correctlyremoveHighlights()removesselected-slotfrom all.calendar-cell-elements. All selections are properly cleared before new ones are addedbooking_blocked()when a collision is detected it must disable both desktop and mobile booking buttons and shows a conflict message.booking_blocked_on_first_touch()displays a message when user only select a single time slot. this feature helps the user to understand what the current selection state is of the calendar toolformatStart(slotId)returns a correctly formatted timestamp from the date pickerformatEnd(slotId)returns a timestamp 30 minutes later. Only with bothformatStartandformatEndthe feature of converting time into start and end slots can be verifiedupdateForms(from, to, roomId)sets all form values correctly (both desktop and mobile) to ensure that the selected values are passed to the form elements used for the submission
FIXED: in mobile mode (only), it is possible to select time slots that are booked already. in desktop mode you get an error message.
The project has been moved to render.com for deployment. The reasons are simple:
- deployments are easy and less "risky"
- build commands, such as
pip install -4 requirements.txt && python manage.py collectstatic --noinput - in case of issues, there is a powershell on render.com (which is affordable)
Deployment:
- prepare requirements.txt, incl.
gunicornandwhitenoise - prepare settings.py
DEBUG=FalseALLOWED_HOSTS=['".onrender.com", "schallplatte.onrender.com"']- use whitenoise when
DEBUG=Falseif not DEBUG: STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
- run the command in the bash
python manage.py collectstatic --noinput - go to render.com
- create a new web service
- connect github repository to render.com
- enter the build command (recommended):
pip install -r requirements.txt && python manage.py collectstatic --noinput - enter start command:
gunicorn schallplatte.wsgi:application - enter environment variables, such as
SECRET_KEY,DEBUG=False,ALLOWED_HOSTS=.onrender.com(or similar),DATABASE_URL
- ensure that collectstatic really was done, in case of doubt, run collectstatic in the powershell on onrender.com directly (not local)
how to change formatting in the command line text - by joeld at https://stackoverflow.com/questions/287871/how-do-i-print-colored-text-to-the-terminal
-
django:
-
extend allAuth's user data
-
numeric loops in html templates with django
-
concatenate strings in django templates with appname_extras.py
-
-
js select multiple cells
I used several pictures from pexels.com (free use) and 2 images from istock, of which i own a standard license. The image files can be found under static/img/free and static/img/istock. The logo was created with OpenAI (chatgpt), which is for educational purpose only. schallplatte01.jpg by Pixabay on pexels.com
- schallplatte02.jpg by cottonbro studio on pexels.com
- schallplatte03.jpg by Pavel Danilyuk on pexels.com
- schallplatte04.jpg by ArtHouse Studio on pexels.com
- schallplatte05.jpg by Pavel Danilyuk on pexels.com
- schallplatte06.jpg by RDNE Stock project on pexels.com
- schallplatte07.jpg by Pavel Danilyuk on pexels.com
- schallplatte08.jpg by Dima Pavlenko on pexels.com
- schallplatte09.jpg by RDNE Stock project on pexels.com
- schallplatte10.jpg by cottonbro studio on pexels.com
- schallplatte11.jpg by me (my own picture)
- schallplatte12.jpg by me (my own picture)
- schallplatte13.jpg by RDNE Stock project on pexels.com
- schallplatte14.jpg by cottonbro studio on pexels.com
- schallplatte15.jpg by cottonbro studio on pexels.com
- schallplatte16.jpg by Keyur Bhalani on pexels.com
- schallplatte17.jpg by Pixabay on pexels.com
- schallplatte18.jpg by Moliv Fotografia on pexels.com
istock photos (with license!)
-
istock01 by gorodenkoff on istockphoto.com
-
istock02 by Saha_Litt on istockphoto.com
You can clone the repository by following these steps:
- Go to the GitHub repository
- Locate the Code button above the list of files and click it
- Select if you prefere to clone using HTTPS, SSH, or Github CLI and click the copy button to copy the URL to your clipboard
- Open Git Bash
- Change the current working directory to the one where you want the cloned directory
- Type git clone and paste the URL from the clipboard git clone https://github.com/YOUR-USERNAME/YOUR-REPOSITORY 7.Press Enter to create your local clone.
To fork the repository by following these steps:
- Go to the GitHub repository
- Click on Fork button in upper right hand corner
I'd like to thank CodeInstitute for that (to be honest) quite challenging opportunity to learn web development. Finally, I'd like to thank my Mentor Mo Shami. He understands to let me learn but can say no when I need it.




































































