{"id":15689273,"url":"https://github.com/christophevg/howifeel","last_synced_at":"2026-03-04T21:03:17.804Z","repository":{"id":137514675,"uuid":"453489394","full_name":"christophevg/howifeel","owner":"christophevg","description":" a small 1-hour project to show newbe developers what coding is all about","archived":false,"fork":false,"pushed_at":"2024-08-03T20:41:56.000Z","size":11376,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-30T18:55:27.889Z","etag":null,"topics":["example","social-network"],"latest_commit_sha":null,"homepage":"https://howifeel.app.homemadebycvg.com","language":"HTML","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/christophevg.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-29T18:50:30.000Z","updated_at":"2024-08-03T20:41:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"7aa2ddad-8a6f-431c-97c3-ae90aa878992","html_url":"https://github.com/christophevg/howifeel","commit_stats":{"total_commits":55,"total_committers":1,"mean_commits":55.0,"dds":0.0,"last_synced_commit":"79825f3f293a08588c2770aa05bb198451bca673"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/christophevg/howifeel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophevg%2Fhowifeel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophevg%2Fhowifeel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophevg%2Fhowifeel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophevg%2Fhowifeel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/christophevg","download_url":"https://codeload.github.com/christophevg/howifeel/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/christophevg%2Fhowifeel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30092883,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T20:42:30.420Z","status":"ssl_error","status_checked_at":"2026-03-04T20:42:30.057Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["example","social-network"],"created_at":"2024-10-03T18:01:30.724Z","updated_at":"2026-03-04T21:03:12.784Z","avatar_url":"https://github.com/christophevg.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# How I Feel\n\n\u003e a small 1-hour project to show newbe developers what coding is all about\n\n## Rationale\n\nStarting in today's world of development of software can be daunting. Especially because the beginnings are so far apart from what we've come acustomed to when using that same software. Starting with \"hello world\" seems so utterly uninteresting that it takes a big effort to get past those first few days, before one reaches the level that something semi-useful can be created.\n\nThis repository is an experiment to start from a completely blanc directory and end up with an actual, useable piece of software. Each commit is a step in this experiment, described in the paragraphs below. The goal is _not_ to learn every step by heart, but to go through the entire process of conceiving and actually implementing a small real-world application. A way to get a realistic overview of what lies at the end of that first long stretch of new knowledge.\n\n## Prerequisites\n\nThe following tools are needed and might first need some installation or creation of an account.\n\n* A unix-like environment, say MacOS, Linux,... Why? Because that's what I use. You migth get away with Windows. I won't be here to help, sorry :-( A unix-like environment comes with a terminal, which allows you to give commands to the system. On MacOS, the Terminal application looks like this: ![Terminal](media/terminal.png)\n* An editor, something to write code with. Here personal flavour kicks in. I like [TextMate](https://macromates.com), you might like something else. Please, don't hurt yourself, don't like [notepad](https://en.wikipedia.org/wiki/Windows_Notepad).\n* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)\n* A [GitHub account](https://github.com/join)\n* [python](https://www.python.org/downloads/)\n* [pyenv](https://christophe.vg/technology/Pyenv-Notes) - I refer to my own installation instruction page. You can also consult [the official pyenv documentation](https://github.com/pyenv/pyenv), which is also hosted on GitHub.\n* A [Heroku account](https://signup.heroku.com)\n* [MongoDB](https://docs.mongodb.com/manual/installation/)\n\n## The Goal\n\nWe want to make a little web application that allows a user to log in and set his/her current mood - expressed as red, yellow or green.\n\nBesides that, the user can create unique links to distribute to others, that can use that link to consult the user's mood. Those links can be deleted, removing access to certain users.\n\n## 19:21 - git init, README.md, git push\n\nOpen up a terminal, create a directory to work in and initialize your git repository. Git repository? Git is a tool that allows you to keep track of your code as you write it.\n\n```zsh\nxtof@sokudo Workspace % mkdir howifeel\nxtof@sokudo Workspace % cd howifeel\nxtof@sokudo howifeel % git init\nInitialized empty Git repository in /Users/xtof/Workspace/howifeel/.git/\nxtof@sokudo howifeel % \n```\n\nBecause this repository contains both the application, aswell as the supporting story about writing it, I started with a first file: `README.md`, the very one you're reading right now. It's good practice to document your code, so I advise you to also always write one. It won't contain al the details of this one, but should at least include some basic information about how to install and run your application and how to contact you in case there is a problem.\n\nIn this case, you can contact _me_ through [GitHub Discussions](https://github.com/christophevg/howifeel/discussions/1) ;-)\n\nNow time to fire up a few other git commands:\n\n```zsh\nxtof@sokudo howifeel % git add README.md\nxtof@sokudo howifeel % git commit -m \"repo init with README\"\n[master (root-commit) 93c438d] repo init with README\n 1 files changed, 78 insertions(+)\n create mode 100644 README.md\n```\n\nThis adds our current changes (the README file) to the \"git repository\" and marks it as a committed sert of changes, along with a small message that explains what this \"commit\" is all about.\n\nThe `.md` extension to the README file tells us that it is written in \"MarkDown\". This is a small, simple, text-oriented markup/layout language that is pretty convenient to write this kind of documentation. Take a look at [the code](https://github.com/christophevg/howifeel/blob/master/README.md?plain=1) that was converted into this visualisation when viewed on GitHub. \n\nNow, we're not done yet. We not only want to track our changes, we also want them to be safe in a place where we can share them. Enter GitHub. Head over to a browser, login to your github account and create a new \"repository\", let's say `howifeel`.\n\nAfter creating the repository in GitHub, we add a reference to it in our own local git repository and \"push\" our changes to it.\n\n```zsh\nxtof@sokudo howifeel % git remote add github git@github.com:christophevg/howifeel.git\nxtof@sokudo howifeel % git push -u github master\nEnumerating objects: 5, done.\nCounting objects: 100% (5/5), done.\nDelta compression using up to 10 threads\nCompressing objects: 100% (4/4), done.\nWriting objects: 100% (5/5), 296.27 KiB | 3.25 MiB/s, done.\nTotal 5 (delta 0), reused 0 (delta 0), pack-reused 0\nTo github.com:christophevg/howifeel.git\n * [new branch]      master -\u003e master\nBranch 'master' set up to track remote branch 'master' from 'github'.\n```\n\nNow refresh the page on GitHub and behold, your first commit is online...\n\n![Hello GitHub](media/github-first-commit.png)\n\nYeah!\n\n## 19:30 - Now What do we Need to Build?\n\nLet's reiterate our \"requirements\":\n\n* a web application\n* users\n* update mood indicator\n* create unique links\n* delete unique links\n\n### A Web Application\n\nEverything is happening online. Of course we want our application to be online. The easiest way to get something online it through the World Wide Web (WWW), which is brought to you by your browser. \n\nWeb applications, running in a browser are created (mainly) using HTML, the Hyper Text Markup Language... after Markdown, the second markup language we encounter and will use to create \"pages\" for our application.\n\nAt this point you have already been using several web applications. If not before today, you have created several accounts as part of the prerequisites.\n\n### Users\n\nWhich brings us to \"users\". Just like GitHub, Heroku,... and so many other web applications, we want our users to be able to create an account to ...\n\n###  Update Mood Indicator\n\n... update their mood and ...\n\n### Create Unique Links\n\n... create unique links, which can be shared with other people.\n\n### Delete Unique Links\n\nAnd sometimes we want to those people to no longer \"follow us\", so we want our users to be able to remove access for those people, by deleting the unique link that was created for them.\n\n### Pages\n\nLet's take 5 steps back: a web application consists of pages. Each page provides a certain functionality. Let's make a list of pages we will need for our application. Think back of your experience with GitHub and Heroku, or Instagram, SnapChat,...\n\n1. frontpage\n2. sign up page\n3. personal mood update page\n4. manage unique links page\n\n### An API\n\nThe web application is merely what runs in your browser. This isn't enough to be able to intertact with your followers. Their browsers won't connect directly to your browser. There is a \"hidden\" part in between: the server. A server does what its name says: it serves your web application to all interested parties: you, your followers,...\n\nFirst of all it serves your pages to the browser. Second, it will process commands that you give using the application in your browser - let's say that I set my mood to \"green\", keep that mood somewhere safe and provide it to my followers when they in their turn consult the server.\n\nThis second part, the processing of commands by the server, is implemented in what is called a Application Programming Interface (API). It's an interface (something you can interact with) that allowd applications (like our web application) to use the server in a programming way. Think of it as a set of commands you can give to the server, for example:\n\n1. show me the frontpage\n2. show me the signup page\n3. create an account with my information\n4. show me my personal mood page\n5. update my personal mood\n6. show me my unique links management page\n7. create a new unique link\n8. delete a unique link\n\nSo, you can see there are basically two types of commands: 1) show me a page and 2) change (create/update/delete) some information.\n\n### A Database\n\nThe server needs to store the information about me and my followers. To do this it needs another server: a database server. In this case we will be using MongoDB. There are many other possibilities. Given for this project, it is the easiest to get started with and doesn't require a lot of background knowledge. You'll thank me for choosing it.\n\nAnd that's it. We have our web application, consisting of 4 pages, an API with 8 commands and a database server.\n\nLet's start writing code...\n\nBut first, we commit this step, because small commits make a happy developer:\n\n```zsh\nxtof@sokudo howifeel % git add README.md \nxtof@sokudo howifeel % git commit -m \"what do we need to build?\"\n[master 4a00af7] what do we need to build?\n 1 file changed, 71 insertions(+)\nxtof@sokudo howifeel % git push\nEnumerating objects: 5, done.\nCounting objects: 100% (5/5), done.\nDelta compression using up to 10 threads\nCompressing objects: 100% (3/3), done.\nWriting objects: 100% (3/3), 1.94 KiB | 1.94 MiB/s, done.\nTotal 3 (delta 1), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (1/1), completed with 1 local object.\nTo github.com:christophevg/howifeel.git\n   2386f56..4a00af7  master -\u003e master\n```\n\n## 19:35 - Hello Bootstrap\n\nStand on the shoulder of giants. It must be your credo when entering the world of code. Choosing the right tools for the job not only consist of a suitable programming language (yes, there is more than one and one doesn't fit all problems), it also means using existing components, modules, packages, frameworks,...\n\nIn this case we are going to leverage the wonderful work initiated by Twitter called [Bootstrap](https://getbootstrap.com). Bootstrap is a collection of HTML and related styling that upgrades your HTML experience to a whole new level. In stead of having to codify every little thing, you can simple think in terms of banners, buttons, etc, up to entire ready-made pages. Take a look at some [examples](https://getbootstrap.com/docs/5.1/examples/) a you'll probably notice a few pages we will happily reuse.\n\nBut first take a peek at [the bootstrap starter template](https://getbootstrap.com/docs/5.1/getting-started/introduction/#starter-template):\n\n```html\n\u003c!doctype html\u003e\n\u003chtml lang=\"en\"\u003e\n  \u003chead\u003e\n    \u003c!-- Required meta tags --\u003e\n    \u003cmeta charset=\"utf-8\"\u003e\n    \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\"\u003e\n\n    \u003c!-- Bootstrap CSS --\u003e\n    \u003clink href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3\" crossorigin=\"anonymous\"\u003e\n\n    \u003ctitle\u003eHello, world!\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003ch1\u003eHello, world!\u003c/h1\u003e\n\n    \u003cscript src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js\" integrity=\"sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p\" crossorigin=\"anonymous\"\u003e\u003c/script\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\nMeet HTML. It consists of \"tag\"-pairs such as `\u003chtml\u003e...\u003c/html\u003e` and `\u003ch1\u003e...\u003c/h1\u003e` that enclose their content and give meaning to it, e.g. `\u003ch1\u003e` marks up a header of the highest level, think of it as your main title.\n\nThere is in fact just a single line in those 15 lines that is really important: `\u003ch1\u003eHello, world!\u003c/h1\u003e`. All other lines are technical mumbojumbo. Save these lines to a file, say `index.html` in a new directory structure, say `src/pages`:\n\n```zsh\nxtof@sokudo howifeel % mkdir -p src/pages\n```\n\n... and open the file in a browser:\n\n![Hello Bootstrap](media/hello-bootstrap.png)\n\nAnd of course ...\n\n```zsh\nxtof@sokudo howifeel % git add README.md \nxtof@sokudo howifeel % git commit -m \"introducing bootstrap and say hello\"\n[master ccac37b] introducing bootstrap and say hello\n 2 files changed, 41 insertions(+)\nxtof@sokudo howifeel % git push \nEnumerating objects: 5, done.\nCounting objects: 100% (5/5), done.\nDelta compression using up to 10 threads\nCompressing objects: 100% (3/3), done.\nWriting objects: 100% (3/3), 1.60 KiB | 1.60 MiB/s, done.\nTotal 3 (delta 1), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (1/1), completed with 1 local object.\nTo github.com:christophevg/howifeel.git\n   53d98d2..ccac37b  master -\u003e master\n```\n\n## 19:46 - Whoops\n\nDarn, I've made a few mistakes while writing this README: the code sections shouldn't be marked as \"zsh\" but \"zsh\", a few links are incoreectly formatted and I made a typo in the last screenshot. Let's edit those and add those changes to our repository.\n\nBefore we commit our changes, git allows us to inspect what we have changed:\n\n```zsh\nOn branch master\nYour branch is up to date with 'github/master'.\n\nChanges not staged for commit:\n  (use \"git add \u003cfile\u003e...\" to update what will be committed)\n  (use \"git restore \u003cfile\u003e...\" to discard changes in working directory)\n\tmodified:   README.md\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n```\n\nGit also allows us to see what we actually changed. You can use the command git diff` for that, though it tends to be a bit harsh on the eye at the beginning. If you install a more graphical tool, like [GitHub Desktop](https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/installing-and-authenticating-to-github-desktop/installing-github-desktop) things become much nicer to look at:\n\n![Github Desktop](media/github-desktop-diff.png)\n\nAnd ...\n\n```zsh\nxtof@sokudo howifeel % git add README.md \nxtof@sokudo howifeel % git commit -m \"fixing some mistakes\"\n[master 42bcc08] fixing some mistakes\n 1 file changed, 32 insertions(+), 10 deletions(-)\nxtof@sokudo howifeel % git push\nEnumerating objects: 5, done.\nCounting objects: 100% (5/5), done.\nDelta compression using up to 10 threads\nCompressing objects: 100% (3/3), done.\nWriting objects: 100% (3/3), 1.07 KiB | 1.07 MiB/s, done.\nTotal 3 (delta 1), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (1/1), completed with 1 local object.\nTo github.com:christophevg/howifeel.git\n```\n\nOur changes are now also viewable [on GitHub](https://github.com/christophevg/howifeel/commit/42bcc088b551b0bceb26dbc25de472948a8f3e78?diff=split), ready to be inspected by anyone interested in our code:\n\n![Github diff](media/github-diff.png)\n\n## 19:51 - Meet Python\n\nBefore we cruise on let's take 5 minutes to setup our coding environment. We'll be using the programming language called [Python](https://www.python.org/). I personally got into python roughly 10 years ago during my [renewed studying experience/experiment](https://christophe.vg/about/Revisiting_Higher_Education).\n\nAnd I have never looked back ;-) Python is a wonderful, versatile, non-nonse language that allows you to quickly write something without too much fuzz, and just as well is allows you to construct beautifully structured larger code bases. One of the great things about Python is its vast and high-quality collection of modules. We'll see some of those as we move forward. Remember our \"standing on the shoulders of giants\" credo? The Python community really excells at this.\n\nAnother good practice you should adopt is to use \"virtual environments\". Virtual environments allow you to seemingly operate in a world solely dedicated to your single application. You can install Python modules, without interfering with other application on you machine. You could even use different Python versions. To manage such a virtual environment, I like to use \"pyenv\". Two commands create the virtual environment and activate it for this directory. It will even be re-activated everytime we enter this directory, based on the `.python-version` file, and our shell shows this by prefixing our prompt with the name of the virtual environment.\n\n```zsh\nxtof@sokudo howifeel % pyenv virtualenv howifeel\nLooking in links: /var/folders/nq/xvzwtwsj25727ybthkp1wmhr0000gn/T/tmp8blbswbs\nRequirement already satisfied: setuptools in /Users/xtof/.pyenv/versions/3.8.12/envs/howifeel/lib/python3.8/site-packages (56.0.0)\nRequirement already satisfied: pip in /Users/xtof/.pyenv/versions/3.8.12/envs/howifeel/lib/python3.8/site-packages (21.1.1)\nxtof@sokudo howifeel % pyenv local howifeel\n(howifeel) xtof@sokudo howifeel % cat .python-version \nhowifeel\n```\n\nEverything we do from now on, will only be executed and applied within the scope of this virtual environment. If we're ever done with it, we can even just throw it away without any garbage to clean up.\n\nPython can be used using the `python` application, which can be given a file with python code in it, or you can just start it and feed it one command at a time. So you can do this:\n\n```zsh\n(howifeel) xtof@sokudo howifeel % python\nPython 3.8.12 (default, Nov  6 2021, 10:34:02) \n[Clang 13.0.0 (clang-1300.0.29.3)] on darwin\nType \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n\u003e\u003e\u003e print(\"Hello World\")\nHello World\n\u003e\u003e\u003e \n```\n\n.. or you can create a file and execute that:\n\n```zsh\n(howifeel) xtof@sokudo howifeel % echo 'print(\"Hello World\")' \u003e hello.py\n(howifeel) xtof@sokudo howifeel % cat hello.py \nprint(\"Hello World\")\n(howifeel) xtof@sokudo howifeel % python hello.py \nHello World\n```\n\nThe former really comes in handy to quickly test something before creating your actual code files.\n\nAnd you know the drill..\n\n```zsh\n(howifeel) xtof@sokudo howifeel % git status\nOn branch master\nYour branch is up to date with 'github/master'.\n\nChanges not staged for commit:\n  (use \"git add \u003cfile\u003e...\" to update what will be committed)\n  (use \"git restore \u003cfile\u003e...\" to discard changes in working directory)\n\tmodified:   README.md\n\nUntracked files:\n  (use \"git add \u003cfile\u003e...\" to include in what will be committed)\n\t.python-version\n\thello.py\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n(howifeel) xtof@sokudo howifeel % rm hello.py\n(howifeel) xtof@sokudo howifeel % echo \".python-version\" \u003e\u003e .gitignore\n(howifeel) xtof@sokudo howifeel % git status\nOn branch master\nYour branch is up to date with 'github/master'.\n\nChanges not staged for commit:\n  (use \"git add \u003cfile\u003e...\" to update what will be committed)\n  (use \"git restore \u003cfile\u003e...\" to discard changes in working directory)\n\tmodified:   README.md\n\nUntracked files:\n  (use \"git add \u003cfile\u003e...\" to include in what will be committed)\n\t.gitignore\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n(howifeel) xtof@sokudo howifeel % git add .gitignore \n(howifeel) xtof@sokudo howifeel % git add README.md \n(howifeel) xtof@sokudo howifeel % git commit -m \"introducing python and virtual environments\"\n[master bbfc043] introducing python and virtual environments\n 2 files changed, 52 insertions(+)\n create mode 100644 .gitignore\n(howifeel) xtof@sokudo howifeel % git push\nEnumerating objects: 6, done.\nCounting objects: 100% (6/6), done.\nDelta compression using up to 10 threads\nCompressing objects: 100% (3/3), done.\nWriting objects: 100% (4/4), 2.13 KiB | 2.13 MiB/s, done.\nTotal 4 (delta 1), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (1/1), completed with 1 local object.\nTo github.com:christophevg/howifeel.git\n   98d8d72..bbfc043  master -\u003e master\n```\n\nBefore adding and committing, I inspected the changes. The `hello.py` test file can be removed, and what about the `.python-version` file? Well, it can't be removed, and it shouldn't be part of the repository, since someone else might call the environment differently, or even use another environment manager (yes there are more ;-)). So we tell git to ignore it.\n\n## 19:54 - Time to Serve\n\nWith python up and running in a virtual environment, it's time bring things more in line with out goal. Our \"Hello World\" page is currently just a file on our own machine, in our own repository and also [on GitHub](https://github.com/christophevg/howifeel/blob/master/src/pages/index.html). In its current form, it won't be accessible by our users and their followers. As said before, we need a server component. Let's introduce that now.\n\nFirst we install `flask` and `gunicorn`, two python packages. The former is a framework for creating web applications, more specifically, the server side. The latter is a framework to actually serve the web application. You could do without, since flask can be run simply using python. Using gunicorn, allows us to work in the same way as Heroku will serve our application. Doing things correct from the beginning is always a good idea.\n\nTo install python packages we use the Package Installer for Python, short `pip`:\n\n```zsh\n(howifeel) xtof@sokudo howifeel % pip install flask\nCollecting flask\n  Using cached Flask-2.0.2-py3-none-any.whl (95 kB)\nCollecting click\u003e=7.1.2\n  Using cached click-8.0.3-py3-none-any.whl (97 kB)\nCollecting Jinja2\u003e=3.0\n  Downloading Jinja2-3.0.3-py3-none-any.whl (133 kB)\n     |████████████████████████████████| 133 kB 2.8 MB/s \nCollecting itsdangerous\u003e=2.0\n  Using cached itsdangerous-2.0.1-py3-none-any.whl (18 kB)\nCollecting Werkzeug\u003e=2.0\n  Using cached Werkzeug-2.0.2-py3-none-any.whl (288 kB)\nCollecting MarkupSafe\u003e=2.0\n  Using cached MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl (18 kB)\nInstalling collected packages: MarkupSafe, Werkzeug, Jinja2, itsdangerous, click, flask\nSuccessfully installed Jinja2-3.0.3 MarkupSafe-2.0.1 Werkzeug-2.0.2 click-8.0.3 flask-2.0.2 itsdangerous-2.0.1\nWARNING: You are using pip version 21.1.1; however, version 22.0 is available.\nYou should consider upgrading via the '/Users/xtof/.pyenv/versions/3.8.12/envs/howifeel/bin/python3.8 -m pip install --upgrade pip' command.\n(howifeel) xtof@sokudo howifeel % pip install --upgrade pip\nRequirement already satisfied: pip in /Users/xtof/.pyenv/versions/3.8.12/envs/howifeel/lib/python3.8/site-packages (21.1.1)\nCollecting pip\n  Downloading pip-22.0-py3-none-any.whl (2.1 MB)\n     |████████████████████████████████| 2.1 MB 2.5 MB/s \nInstalling collected packages: pip\n  Attempting uninstall: pip\n    Found existing installation: pip 21.1.1\n    Uninstalling pip-21.1.1:\n      Successfully uninstalled pip-21.1.1\nSuccessfully installed pip-22.0\n(howifeel) xtof@sokudo howifeel % pip install gunicorn\nCollecting gunicorn\n  Using cached gunicorn-20.1.0-py3-none-any.whl (79 kB)\nRequirement already satisfied: setuptools\u003e=3.0 in /Users/xtof/.pyenv/versions/3.8.12/envs/howifeel/lib/python3.8/site-packages (from gunicorn) (56.0.0)\nInstalling collected packages: gunicorn\nSuccessfully installed gunicorn-20.1.0\n```\n\nRemark that pip tells us that our version of pip is outdated and nicely tells us how to upgrade it.\n\nTime to create our first \"server\". Create a file `server.py`:\n\n```python\nimport os\nfrom flask import Flask, render_template\n\ntemplate_dir = os.path.abspath(\"src/pages\")\napp = Flask(__name__, template_folder=template_dir)\n\n@app.route(\"/\")\ndef hello():\n  return render_template('index.html')\n```\n\nand run it ...\n\n```zsh\n(howifeel) xtof@sokudo howifeel % gunicorn server:app\n[2022-01-30 19:30:11 +0100] [93015] [INFO] Starting gunicorn 20.1.0\n[2022-01-30 19:30:11 +0100] [93015] [INFO] Listening at: http://127.0.0.1:8000 (93015)\n[2022-01-30 19:30:11 +0100] [93015] [INFO] Using worker: sync\n[2022-01-30 19:30:11 +0100] [93032] [INFO] Booting worker with pid: 93032\n```\n\nand visit [http://localhost:8000](http://localhost:8000) ...\n\n![Hello Server](media/hello-server.png)\n\nEt voila ... you have created your first web application, with one page and a server component with an API that serves that one page. If you go back and look at what we wanted to achieve, we now have an embryonal version of what we need up and running. Except...\n\nBut first:\n\n```zsh\n(howifeel) xtof@sokudo howifeel % git status\nOn branch master\nYour branch is up to date with 'github/master'.\n\nChanges not staged for commit:\n  (use \"git add \u003cfile\u003e...\" to update what will be committed)\n  (use \"git restore \u003cfile\u003e...\" to discard changes in working directory)\n\tmodified:   README.md\n\nUntracked files:\n  (use \"git add \u003cfile\u003e...\" to include in what will be committed)\n\t__pycache__/\n\tserver.py\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n(howifeel) xtof@sokudo howifeel % echo \"__pycache__\" \u003e\u003e .gitignore\n(howifeel) xtof@sokudo howifeel % git add .gitignore\n(howifeel) xtof@sokudo howifeel % git add server.py\n(howifeel) xtof@sokudo howifeel % git add README.md \n(howifeel) xtof@sokudo howifeel % git commit -m \"enter the server\"\n[master 0a1807b] enter the server\n 3 files changed, 81 insertions(+)\n create mode 100644 server.py\n(howifeel) xtof@sokudo howifeel % git push\nEnumerating objects: 11, done.\nCounting objects: 100% (11/11), done.\nDelta compression using up to 10 threads\nCompressing objects: 100% (6/6), done.\nWriting objects: 100% (7/7), 523.95 KiB | 4.90 MiB/s, done.\nTotal 7 (delta 2), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (2/2), completed with 2 local objects.\nTo github.com:christophevg/howifeel.git\n   c13bae6..0a1807b  master -\u003e master\n```\n\n## 20:01 - Go Online\n\nOur web application is currently running on our machine. No one but us can access `http://localhost:8000`. If we want people to be able to use it, we need to get it online. Yes, it's available on GitHub, but GitHub won't \"serve\" it. To do that, we resort to Heroku, a Cloud service provider, that is so kind to offer a free tier for small projects.\n\nHead over to Heroku and create an application, connect it to our GitHub repository and enable automatic deploys every time we push our changes to GitHub:\n\n![Heroku Create App](media/heroku-create-app-1.png)\n\n![Heroku Create App](media/heroku-create-app-2.png)\n\n![Heroku Connect Github](media/heroku-connect-github.png)\n\n![Heroku Automatic Deploy](media/heroku-automatic-deploy.png)\n\nNow we only have to add two more files, to tell Heroku how to actually serve our application, a file called `Procfile` (yes without any extension):\n\n```\nweb: gunicorn server:app\n```\n\nAnd the list of python packages we are using:\n\n```zsh\n(howifeel) xtof@sokudo howifeel % pip freeze\nclick==8.0.3\nFlask==2.0.2\ngunicorn==20.1.0\nitsdangerous==2.0.1\nJinja2==3.0.3\nMarkupSafe==2.0.1\nWerkzeug==2.0.2\n(howifeel) xtof@sokudo howifeel % pip freeze \u003e requirements.txt\n```\n\nNow, are you ready for this ... ?\n\n```zsh\n(howifeel) xtof@sokudo howifeel % git status\nOn branch master\nYour branch is up to date with 'github/master'.\n\nChanges not staged for commit:\n  (use \"git add \u003cfile\u003e...\" to update what will be committed)\n  (use \"git restore \u003cfile\u003e...\" to discard changes in working directory)\n\tmodified:   README.md\n\nUntracked files:\n  (use \"git add \u003cfile\u003e...\" to include in what will be committed)\n\tProcfile\n  requirements.txt\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\n(howifeel) xtof@sokudo howifeel % git add README.md Procfile requirements.txt\n(howifeel) xtof@sokudo howifeel % git commit -m \"let Heroku serve it\"    \n[master 1442edf] let Heroku serve it\n 3 files changed, 21 insertions(+)\n create mode 100644 Procfile\n create mode 100644 requirements.txt\n(howifeel) xtof@sokudo howifeel % git push\nEnumerating objects: 6, done.\nCounting objects: 100% (6/6), done.\nDelta compression using up to 10 threads\nCompressing objects: 100% (3/3), done.\nWriting objects: 100% (4/4), 995 bytes | 995.00 KiB/s, done.\nTotal 4 (delta 1), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (1/1), completed with 1 local object.\nTo github.com:christophevg/howifeel.git\n   c06b3ea..1442edf  master -\u003e master\n```\n\nNow take a look at your Heroku overview page for your application:\n\n![Heroku Overview Deployment in Action](media/heroku-overview-cd.png)\n\nAnd take a look at the deployment progress...\n\n![Heroku First Deployment](media/heroku-first-deployment.png)\n\nWait ... is that ... a public URL there? Yes it is ... yes it is ...\n\n![Hello Heroku](media/hello-heroku.png)\n\nYou first web application is now online and every commit you push to GitHub will be automatically deployed on Heroku, available for everybody to use.\n\nTake a minute to reflect, because this is an important moment. You now have a complete end-to-end setup for serving a web application. From now on, the focus can be on the actual application, you infrastructure is up and running.\n\n## 20:05 - Constructing our Actual Application\n\nLet's replace the dummy \"Hello World\" page with some actual pages. Here we can take several approaches: we could start with a front page and a sign-up page, actually following the typical user journey. Our we could start with creating just the \"mood update\" page, and see how this gets into our database.\n\nI typically prefer to start with the core functionality, that what it's all about: \"recording my mood\". Expanding it to multiple users can come later. Let's make this first a single-user application (and we keep the multiple users in mind in the meantime ;-))\n\n### Designing our Page\n\nLet's browse once again throuhg the [Bootstrap examples](https://getbootstrap.com/docs/5.1/examples/). The [pricing example](https://getbootstrap.com/docs/5.1/examples/pricing/) seems like a good starting point for presenting and recording my mood. Let's take its source code and dependencies and create a new page `[src/pages/mood.html](src/pages/mood.html)`. It's a bit large to include here, so look at the file and see that I've stripped out some things and modified it to our needs. I've done this in several commits, so in the history of the repository, you can now see what changes I made to modify the original example.\n\nThe example has an additional file dependency: `pricing.css` - I've renamed it to `mood.css`, for obvious reasons. A CSS, or Cascading Style Sheet, defines how HTML elements will be styled. It separated structure from style, which is a good thing, trust me ;-)\n\nCSS files are static files, they don't change. So Flask treaths them as such. We just need to let it know where to find them. Besides that, we also introduce our second API call, the one to get the page to manage our mood. The relevant additions/changes are:\n\n```python\n# ...\n\ntemplate_dir = os.path.abspath(\"src/pages\")\nstatic_dir   = os.path.abspath(\"src/static\")\napp = Flask(__name__, template_folder=template_dir, static_folder=static_dir)\n\n# ...\n\n@app.route(\"/mood\")\ndef mood():\n  return render_template('mood.html')\n```\n\nFire up gunicorn again, and take a look at [http://localhost:8000/mood](http://localhost:8000/mood):\n\n![Mood Page Design](media/mood-page-design.png)\n\nIt's bare bones, it's clear, just the way I like it ;-) Thank you Bootstrap. Now resize your browser a bit...\n\nBootstrap is a responsive framework, which means that it nicely reformats your HTML structure even to accomodate almost all screen sizes. So your application is iPhone ready, without any action from our part. Talk about giant shoulders.\n\n![Mood Page Design Responsive](media/mood-page-design-responsive.png)\n\n### Activating our Page\n\nIf you click on the buttons, nothing happens right now. And that's how it should be. HTML is a markup language for structuring web documents. It's not a programming language that allows us to do things with the HTML elements. To do that we need to introduce another very important language in today's development world: Javascript.\n\n\u003e Why not Python? Good question. Simply because when browsers were born, around 1995, Javascript was introduced and Python was on a different trajectory. Too bad, how nice would it have been to have [Python in a Browser](https://brython.info) ;-)\n\nJust like packages and modules augment the quality of Python, Javascript also has its upgrade: JQuery, a set of Javascript functionality to make working with both Javascript and HTML pages a lot easier.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophevg%2Fhowifeel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchristophevg%2Fhowifeel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchristophevg%2Fhowifeel/lists"}