{"id":15772272,"url":"https://github.com/c-ehrlich/touiteur","last_synced_at":"2025-07-22T10:07:19.667Z","repository":{"id":44404302,"uuid":"382816465","full_name":"c-ehrlich/Touiteur","owner":"c-ehrlich","description":"App for posting 140 character status updates, build in Django and Vanilla JS","archived":false,"fork":false,"pushed_at":"2021-08-28T23:15:10.000Z","size":891,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-11T15:45:47.795Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c-ehrlich.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-07-04T09:53:30.000Z","updated_at":"2022-07-10T15:46:11.000Z","dependencies_parsed_at":"2022-07-15T05:30:36.978Z","dependency_job_id":null,"html_url":"https://github.com/c-ehrlich/Touiteur","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/c-ehrlich/Touiteur","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-ehrlich%2FTouiteur","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-ehrlich%2FTouiteur/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-ehrlich%2FTouiteur/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-ehrlich%2FTouiteur/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c-ehrlich","download_url":"https://codeload.github.com/c-ehrlich/Touiteur/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-ehrlich%2FTouiteur/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266473058,"owners_count":23934477,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-04T15:21:38.460Z","updated_at":"2025-07-22T10:07:19.642Z","avatar_url":"https://github.com/c-ehrlich.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Touiteur\n\n\u003cimg src=\"https://i.imgur.com/yglbghe.png\" width=\"500\"\u003e\n\nTouiteur is a feature-rich Twitter clone with Django + Postgres in the backend and HTML + CSS + JS + a small amount of Bootstrap in the frontend.\n\n[Demo video](https://www.youtube.com/watch?v=2aNYwn2iMns)\n\n## Table of Contents\n\n*   [Installation](#installation)\n*   [Features and Design Considerations](#features-and-design-considerations)\n    *   [Front-End](#front-end)\n    *   [Back-End](#back-end)\n    *   [Database](#database)\n*   [Potential Improvements](#potential-improvements)\n*   [Screenshots](#screenshots)\n\n\n## Installation\n\n### Debug Mode\n1. Install the required packages with `pip install -r requirements.txt`\n2. `./manage.py makemigrations`, `./manage.py migrate`\n3. `django-admin compilemessages` to prepare the i18n files\n4. Run the development server with `python manage.py runserver`\n\n### Deployment\n- The project can easily be deployed with Docker. This requires taking it out of debug mode, disabling Django Debug Toolbar, setting up static file serving, and creating separate containers for the app/db, as well as a (nginx-based) server for static files. \n- While it is possible to get it running on an Alpine image, I would recommend the standard Python image as dealing with setting up the dependencies on Alpine is probably not worth it for a this type of project.\n\n## Features and Design Considerations\n\n### Front-End\n- [x] After creating a new account, there is an onboarding process where the user decides things such as their profile picture, language, theme, and privacy options.\n- [x] The app is fully translated into three languages using i18n. Logged in users see the language they have selected as their preference. Logged out users see the language of their browser locale, or English if their locale is not available.\n- [x] The app has light and dark mode. This is achieved by giving a class to the `\u003cbody\u003e` element based on a user preference, and using CSS variables combined with a themes.css file to determine the color of elements.\n- [x] There are live-updating notifications for mentions (which show up regardless of where the user is) as well as notifications for new posts in the current view.\n- [x] Users can not see posts of users that they are blocked by\n- [x] Posts by blocked accounts are hidden by default, but the user can click a button to reveal them. However they cannot reply.\n- [x] Users can attach images to posts, and can delete their image / select a new one prior to sending the post\n- [x] Users can edit their own posts\n- [x] Each post has a slide-out reply panel that is activated or hidden by clicking the reply button in the post\n- [x] The front-end is written entirely in Vanilla JS (in addition to HTML/Jinja/CSS). This was mostly a decision made for the sake of finding the limits of Vanilla JS.\n\n\n### Back-End\n- [x] All necessary routes are CSRF protected\n- [x] All data is checked prior to processing to not create invalid database items\n    - A user cannot follow a non-existing user, or a user that has blocked them, or themselves\n    - Users can't have the same username (but can have the same display name)\n    - Users cannot reply to posts of users who they have blocked or are blocked by\n    - Nonexistent posts cannot be replied to\n    - etc.\n- [x] All API routes return the simplest possible Json objects\n\n### Database\n- [x] The database is normalized to 3NF\n- [x] All ORM queries use Django features such as prefetch_related, select_related, annotate, etc. to improve performance. The SQL queries to load a page of posts including images, follow and block relationship information, reply counts, etc. typically take between 20-30ms.\n\n## Potential Improvements\n- Currently everything is being run from the main Postgres database. This is not ideal in terms of scaling as for example getting live notifications is quite db intensive. A better design would be to have a separate database, which is optimised for performance (for example Redis), for things that need to be accessed frequently.\n- Adding a Redis database would also allow some additional features that rely on very fast db queries, such as autocomplete/suggestions on usernames.\n- There are some obvious additional features that could be implemented\n  - Reporting posts\n  - Letting admins ban users without having to delete the entire account\n  - Switching from Pagination to infinite scrolling (the decision to use Pagination was based on the CS50web requirements)\n- Vanilla JS is not the best choice in terms of maintainability for the front-end, but it was chosen due to the self-teaching aspect of the project.\n\n## Screenshots\n![Touiteur Screenshot 2](https://i.imgur.com/3ixlhcv.png)\n![Touiteur Screenshot 3](https://i.imgur.com/KT1Z5u3.png)\n![Touiteur Screenshot 4](https://i.imgur.com/n8BiEs3.png)\n![Touiteur Screenshot 5](https://i.imgur.com/J01Ytod.png)\n![Touiteur Screenshot 6](https://i.imgur.com/S9l1nw8.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-ehrlich%2Ftouiteur","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc-ehrlich%2Ftouiteur","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-ehrlich%2Ftouiteur/lists"}