Overview
This is the developer documentation for the code that powers foodsharing.de, foodsharing.at, and foodsharingschweiz.ch.
Useful links
- main site foodsharing.de
- beta site beta.foodsharing.de
- gitlab organisation gitlab.com/foodsharing-dev
- main repo gitlab.com/foodsharing-dev/foodsharing
- issue tracker gitlab.com/foodsharing-dev/foodsharing/issues
- developer chat slackin.yunity.org (channel: #foodsharing-dev)
Die foodsharing-IT sucht Helfer*innen 💻🔧
For the English version please click here.
Liebe*r Interessent*in
es freut uns, dass du dich für dieses Thema interessierst. Wir von foodsharing sind eine Initiative, mit dem Ziel sich gegen Lebensmittelverschwendung einzusetzen. Unsere Homepage ist das zentrale Werkzeug unserer Initiative. Die gesamte Vernetzung untereinander, die gemeinsame Arbeit an verschiedensten Themen und zu guter Letzt die Organisation all unserer Lebensmittelrettungen sind dank dieser Plattform möglich.
Was viele aber nicht wissen: Wir haben mehr als 400.000 registrierte Konten und verschicken hunderttausende Mails pro Monat. Ein riesiger Apparat. Über 100.000 Foodsaver organisieren sich über die Homepage, viele hunderte Botschafter*innen verwalten Regionen im gesamten deutschsprachigen Raum. Demgegenüber stehen nur etwa 5 Programmierer*innen. Daher wollen wir mit diesem aufgefrischten Post jetzt einen neuen Aufruf starten.
Du hast jetzt bereits Lust bekommen?
Melde dich gerne bei Slack im Kanal / Gruppenchat #foodsharing-dev oder sende uns eine Mail an it@foodsharing.network damit wir mit dir gemeinsam mögliche Aufgaben und Betätigungsfelder rund um die unten aufgelisteten Themen für dich finden können. Wenn diese beiden Kontaktwege dich abhalten, kannst du auch gerne Jonathan über die Webseite eine Nachricht schreiben. Wir sind ein tolles Team und wir haben bisher noch für jede*n eine Aufgabe gefunden.
Wo sind all die Freiwilligen mit IT-Kenntnissen?
Wir haben so viele hochaktive und überzeugte Mitstreiter*innen in unserem schönen Projekt. Doch nur so wenige bringen sich bisher in die IT ein. Wo sind denn all die Hobby-Programmierer*innen? Wir müssten bei einer so jungen und frischen Einrichtung doch dutzende haben.
Was benötigen wir?
Programmierer*innen
- Android Programmierer*innen (nativ)
- iOS-Programmierer*innen (nativ)
- Web-Entwickler*innen
Qualitätssicherung
- Beta-Tester*innen
- Issue-Betreuer*innen
- Unit-Test-Entwickler*innen
Design
- Grafikdesigner*innen
- Android-Frontend-Designer*innen (Verbesserung des App-Designs)
Support
- Webseiten-Supporter*innen (deutschsprachig)
- IT-Supporter*innen
- Technische Redakteure
- Recruiter*innen
Wie finden wir mehr Unterstützer*innen?
Frag doch einmal in deinem Bezirk herum. Innerhalb von foodsharing, aber gerne auch außerhalb. Es gibt bestimmt Leute, die sich gerne einbringen möchten, aber keine Lust oder Zeit haben für unser übliches Lebensmittelrettungsprogramm. Du kannst auch gerne Freiwilligenstellen ausschreiben oder auf Infoveranstaltungen nach Interessenten suchen. Du wirst überrascht sein, wie viele Leute heutzutage programmieren können. Hilf uns, diese Personen zu motivieren und zu überzeugen.
Was gibt es zu tun?
Abhängig davon, welche Motivation du mitbringst, findet sich gewiss eine Aufgabe für dich. Mögliche Aufgaben sind unter anderem:
- Die rund 250 derzeit gemeldeten Fehler und Feature-Wünsche angehen
- App für jeweils Android und iOS
- Die vielen Botschafter*innen aber auch Mitglieder bei ihren IT-Problemen zu unterstützen
- Die Plattform ins Englische übersetzen
- Moderation der Issues und Feature-Wünsche
- Auf Freiwilligenplattformen für uns neue Programmierer*innen werben
- ...
Wie kannst du dich einbringen?
Wie schon gesagt, mach ordentlich Werbung für unsere IT und sende den Link zu diesen Informationen hier gerne weiter. Besonders schön wäre es aber natürlich, dich dabei zu haben:
- Schau dich doch mal auf unserem Blog um, oder in unserem Contribution Guide.
- Sieh dir die lange Liste unserer To-dos an. Einige davon sind speziell für Anfänger markiert.
- Besonders freuen wir uns, wenn du in unserem Slack Chat vorbei schaust und wir im Kanal #foodsharing-dev mit dir gemeinsam mögliche Aufgaben und Betätigungsfelder in der IT für dich finden.
- Wenn du unsicher bist oder die englischen Programmierseiten nicht verstehst, dann darfst du uns gerne eine Mail schreiben oder auf Jonathan zukommen. Wir versuchen weiterzuhelfen.
Schick uns auch gerne eine Mail an it@foodsharing.network wo wir weiter darüber sprechen können wie du dich einbringen kannst.
Gibt es nicht noch 'ne nerdige Auflistung, um was es IT-technisch geht?
Aber natürlich:
Webseiten Front- und Backend
- PHP (Symfony 5)
- JavaScript (Webpack, Vue.js)
- HTML (Twig)
- CSS (Bootstrap)
- MySQL
- RESTful APIs
- Git
- Docker Compose development environment
- Codeception für Unit-, API-, and Acceptance-Testing (mit Selenium)
- GitLab CI für Tests und automatisches Deployment (mit php deployer)
Generelles zu den Smartphone Apps
- Das Backend wächst und wird in gemeinsamer Arbeit auf die Bedürfnisse der App Entwickler*innen angepasst
- Beim Setup wirst Du durch die Infos in der Gitlab Readme und durch uns unterstützt
- Die Roadmap bestimmst Du maßgeblich selbst mit
- Screen- / Workflow-Designer für ein grundlegendes Design sind hier auch sehr willkommen
- Wertvolle Unterstützung durch den CI-Prozess
Google Android App:
- Kotlin als Sprache soweit wie möglich
- REST/APIs (retrofit)
- Dependency injection (dagger)
- Reactive programming (reactivex)
Apple iOS App:
- Carthage als Packet Manager
- Die grundlegende Architektur der App baut auf ReSwift auf
- Views werden im Code, mit AutoLayout und Constraints erzeugt
- Als UI Architektur wird RxSwift verwendet
- Coordinator Pattern als Screenflow
Hackweeks
Um noch enger Hand in Hand zu arbeiten, treffen wir uns regelmäßig zu Hackweeks. Hier sind alle Teilnehmer*innen willkommen, die das Ziel haben, an der Entwicklung mitzuwirken.
Hier ein paar Artikel über die letzte Hackweek:
Ankündigungen für Hackweeks findest du im Slack Channel #foodsharing-hackweek und im Foodsharing-Blog.
Danke!
Danke dir, dass du so lange gelesen hast. Mit einer fitten IT hätten wir so viel mehr Potential und es wäre natürlich generell toll, die vielen Aufgaben auf viele Schultern zu verteilen. Mit einem noch cooleren IT-Team können wir in guter Stimmung eigentlich alles umsetzen, was wir uns wünschen. Und man lernt nebenbei 'nen ganzen Haufen spannenden Kram. Wir freuen uns schon sehr darauf, dich und deine Bekannten bald im Team willkommen zu heißen.
📣📣 Vielleicht ist es leider wirklich nichts für dich, schicke aber bitte Du trotzdem jemanden den Link zu dieser Seite. Damit HILFST DU uns und somit der ganzen Community WIRKLICH SEHR. ❤️ ❤️ https://devdocs.foodsharing.network/it-tasks.html
Herzliche Grüße von Deinem IT-Team! it@foodsharing.network
The foodsharing IT is looking for helpers 💻🔧
Eine Deutsche Version ist hier zu finden.
Dear potentially interested person,
We are pleased that you are interested in this topic. We at foodsharing (link to page in German) are an initiative to fight food waste. Our homepage is the central tool of our initiative. This platform enables the entire networking among each other, the common work on different topics and last but not least the organisation of all our food rescues.
Did you know that we currently have more than 400.000 registered accounts and send out hundreds of thousands of emails every month? Beyond 100.000 food savers are organised via the homepage, and several hundreds ambassadors (Botschafter) administer a wide variety of regions throughout the German-speaking world. A giant apparatus! However, there are only about 5 programmers. That's why we want to launch a new call with this refreshed post.
Have we gotten you interested?
Feel free to contact us on Slack in the channel / group chat #foodsharing-dev or send us an email to it@foodsharing.network so that we can find together some possible tasks and fields of activity around the topics listed below for you. Should these two ways of contact keep you away, you can also write a message to Jonathan via the website. We are a great team and so far we have found a task for everyone who wanted to help.
Where are all the volunteers with IT skills?
We have so many highly active and committed volunteers in our marvellous project. But only a few of them are involved in IT so far. Where are all the hobby programmers? One might expect to find dozens at such a young and fresh institution.
What do we need?
Programmers
- Android Programmers (native)
- iOS programmers (native)
- web developers
quality assurance
- Beta testers
- issue managers
- Unit Test Developers
design
- graphic designers
- Android front-end designers (improvement of app design)
support
- Website supporters (German-speaking)
- IT supporters
- Technical Editors
- recruiters
How do we find more supporters?
Ask around in your district: Inside foodsharing, but also outside. There are certainly people who would like to get involved, but have no desire or time for our usual food rescue program. You can also advertise volunteer positions or search for interested people at information events. You'll be surprised how many people can program these days. Help us motivate and convince these people.
What is there to do?
Depending on the motivation you bring along, there will certainly be a task for you. Possible tasks are among others:
- Approximately 250 currently reported bugs or feature requests are to be addressed
- App for Android and iOS respectively
- To support the many ambassadors as well as members with their IT problems
- Translating the platform into English
- Moderation of issues and feature requests
- Recruit new programmers for us on volunteer platforms
- ...
How can you get involved?
As already said, you can do some good advertising for our IT and send the link to this information here. But of course it would be especially nice to have you here:
- Have a look around on our blog or in our Contribution Guide.
- Have a look at the long list of our To-dos. Some of them are specially marked for beginners.
- We are especially happy if you drop by in our Slack Chat and we find together with you possible tasks and fields of activity in IT for you in the channel #foodsharing-dev.
- If you are unsure or don't understand the English programmer pages, you are welcome to send us an email or approach Jonathan. We'll try to help you.
We would also be happy to receive an email to it@foodsharing.network and to talk about how you can get involved.
Isn't there some kind of nerdy listing in tech speak that states, what is needed?
For sure:
Website Front- and Backend
- PHP (Symfony 5)
- JavaScript (Webpack, Vue.js)
- HTML (Twig)
- CSS (Bootstrap)
- MariaDB
- RESTful APIs
- Git
- Docker Compose development environment
- Codeception for Unit-, API-, and Acceptance testing (with Selenium)
- GitLab CI for tests and automatic deployment (with php deployer)
General information for the smartphone app
- The backend grows and is cooperatively being adapted to the needs of the app developers
- During the setup you will be supported by the information in the Gitlab Readme and by us
- The roadmap is determined to a large extent by the roadmap itself
- Screen / workflow designers for a basic design are also very welcome here
- Valuable support through the CI process
Google Android App:
- Kotlin as language as far as possible
- REST/APIs (retrofit)
- dependency injection (dagger)
- Reactive programming (reactivex)
Apple iOS App:
- Carthage as Packet Manager
- The basic architecture of the app is based on ReSwift
- Views are created in code, with AutoLayout and constraints
- RxSwift is used as UI architecture
- Coordinator Pattern as Screenflow
Hackweeks
In order to work even more closely together, we meet regularly for Hackweeks. Here all participants are welcome to participate in the development.
Here are some articles about the last Hackweek:
Announcements for Hackweeks can be found in the Slack Channel #foodsharing-hackweek and on the Foodsharing Blog (German only).
Thank you!
Thank you for reading so long. With a fit IT we have so much more potential and of course it would be great to distribute the many tasks on many shoulders. With an even cooler IT team, we can do whatever we want in a good mood. And you learn a whole bunch of exciting stuff on the side. We are really looking forward to welcoming you and your friends to the team soon.
📣📣 Maybe it's really not for you, but please send someone the link to this page. So YOU CAN HELP us and thus the whole community A LOT! ❤️ ❤️
https://devdocs.foodsharing.network/it-tasks_EN.html
Best regards from your IT team! it@foodsharing.network
Tools installation
Klicke hier für die Deutsche Version.
We use Docker containers and Docker Compose for our build setup. Hence, everything is build and run withing containers and you only need to have Docker and Git on your machine. There's no need to install additional development tools, as all the necessary tools are all bundled in the development containers.
You can use the Docker Compose setup, if you are using one of the following systems:
- Linux (64bit)
- OSX Yosemite 10.10.3 or higher
- Windows 10 Pro or higher
If you are not using one of those, then try the Vagrant + Docker Compose setup.
Descriptions for the different operating system follow:
Linux
In a recent Linux distribution you can probably install Docker just via the package manager of the distribution. Please note that at least version 1.6.0 of Docker Compose is needed. For Debian or Ubuntu the following command line would work for example:
sudo apt install docker.io docker-compose
In case that Docker or Docker Compose are not available in a recent version via the package manager of your distribution, please follow the documentation for the Docker CE Installation and the Docker Compose Installation.
Make sure that your user is in the docker
group. Otherwise, there would be access errors, when trying to run a docker container:
sudo usermod -aG docker $USER
Either logout and login again to reload the groups or run (for each shell...)
su - $USER
You should now be able to connect to Docker without errors. Try that by executing:
docker info
You can now continue with getting & running the code.
OSX Yosemite 10.10.3 or higher
Install Docker for Mac (direct link).
You can afterwards continue with getting & running the code.
Windows
It should be setup unter the wsl (Windows Subsystem for Linux) environment. The folder can be accessed with:
\\wsl$
Windows Subsystem for Linux 2 (WSL 2)
- Install Ubuntu via the Microsoft Store and start it
- Install Windows Terminal via the Microsoft Store and start it
- Open a new tab in Windows Terminal with Ubuntu
- Add the following to
~/.bashrc
with a text editor (e.g. nano)
export DOCKER_HOST=tcp://localhost:2375
export DOCKER_BUILDKIT=1
- Check in that your environment is active in: Docker Settings -> Resources -> WSL Integration
You can now continue with getting & running the code.
Windows Subsystem for Linux 1 (WSL 1)
Install Docker for Windows (direct link) and Git for Windows.
If you are using Windows 10 Home, make sure you fulfill all system requirements and then install both Docker Desktop on Windows Home and Git for Windows.
It is important to grant docker access to C: (in the graphical docker interface: settings -> resources -> filesharing -> mark C, apply and restart)
You can test your docker in the command shell (e.g. cmd or powershell) with the command docker --version
. If it shows something, you're good to go.
Restart your Windows now.
There is a graphical user interface to administrate the repo, which is recommended for Git beginners.
But you can use the Git Bash shell just like in Linux to clone it:
git clone git@gitlab.com:foodsharing-dev/foodsharing.git foodsharing
After this command, your files will be found in the folder %UserProfile%\foodsharing
To start the containers, use the Git Bash shell:
cd foodsharing
./scripts/start
The first time you run the start script, which takes a lot of time, you probably have to give the windows firewall the OK to let Docker work.
Known Issues on Windows
General
If something is wrong, please check in your task manager under "performance" if the virtualisation is activated and troubleshoot if necessary.
git trouble (on WSL1)
If git does not working well, please do:
cd foodsharing/bin
tr -d '\15' < console > console
Make sure not to commit the console
file and maybe discuss further steps with the team.
[RuntimeException]
If you get a [RuntimeException]
, let ./scripts/start
run again and again and maybe even again until it's done.
yarn lint
There is a known bug concerning yarn, see: https://github.com/yarnpkg/yarn/issues/7187 and https://github.com/yarnpkg/yarn/issues/7732 and https://github.com/yarnpkg/yarn/issues/7551
Changes in js, vue etc. aren't showing up
In order to have the webpack-dev-server recognize changes you have to add this watchOptions block to client/serve.config.js
[...]
module.exports = {
[...]
devServer: {
watchOptions: {
poll: true
},
[...]
Note: Please make sure not to commit this file afterwards with your changes.
Vagrant
If you cannot use any of the above methods, then this should work with every common operation system.
However, we are less familiar with this solution, so we may be less able to support you.
Install VirtualBox and Vagrant.
Then:
git clone git@gitlab.com:foodsharing-dev/foodsharing.git foodsharing
cd foodsharing
vagrant up
Daily work
vagrant up
starts the machine and foodsharing project.
vagrant halt
stops the virtual machine.
vagrant ssh
connects to the virtual machine.
Once connected to the virtual machine, go to /vagrant with cd /vagrant
.
This is where the foodsharing folder is mounted in the VM.
From there on, you can run all scripts with ./scripts/NAME
.
Note:
./scripts/start
will always be executed, when you start the virtual machine with vagrant up
.
There is a known bug when running VirtualBox + nginx that nginx serves files from a memory cache. If you encounter this problem, then it can probably be fixed by emptying the memory cache with sync; sudo sh -c "/bin/echo 3 > /proc/sys/vm/drop_caches"
or even running this every second with watch -n 1 'sync; sudo sh -c "/bin/echo 3 > /proc/sys/vm/drop_caches"'
.
Installation der nötigen Software
Click here for the English version.
Wir benutzen Docker-Container und Docker Compose für unsere Build- und Testumgebung.
Du kannst das "Docker Compose"-Setup benutzen, falls du mit einemder folgenden Systeme arbeitest:
- Linux (64bit)
- OSX Yosemite 10.10.3 oder neuer
- Windows 10 Pro oder neuer
Falls du keins davon benutzt, probiere es mit dem "Vagrant + Docker Compose"-Setup.
In den folgenden Abschnitten ist die Installation für die verschiedenen Systeme beschrieben:
Linux
In aktuellen Linux-Distributionen kannst du Docker wahrscheinlich einfach über den Paketmanager installieren. Stelle dabei nur sicher, dass Docker Compose mindestens in Version 1.6.0 verfügbar ist. Unter Debian oder Ubuntu sollte die Installation zum Beispiel über folgende Kommandozeile klappen:
sudo apt install docker.io docker-compose
Falls Docker oder Docker Compose nicht in einer aktuellen Version im Paketmanager verfügbar sind, folge bitte den Anleitungen für die Installation von Docker CE und Docker Compose.
Stelle sicher, dass dein Benutzer in der docker
-Gruppe ist. Ansonsten wird es zu Rechtefehlern kommen, wenn du später versuchst einen Docker-Container zu starten:
sudo usermod -aG docker $USER
Dann logge dich entweder noch einmal neu ein oder lade die Gruppen neu oder führe (in jedem Terminal) aus: su - $USER
Jetzt solltest du dich ohne Fehler verbinden können. Teste das, indem du folgendes ausführst:
docker info
Du kannst dir jetzt den Quellcode holen und ausführen.
OSX Yosemite 10.10.3 oder darüber
Installiere Docker for Mac (direct link).
Danach kannst du dir den Quellcode holen und ausführen.
Windows
Wir empfehlen, es unter wsl (Windows Subsystem for Linux) zu installieren. Auf den Ordner kann mit dieser Zeile zugegriffen werden: ''' \wsl$ '''
Windows Subsystem for Linux 2 (WSL 2)
- Installiere Ubuntu über den Microsoft Store und starte es
- Installiere das Windows Terminal über den Microsoft Store und starte es
- Öffne einen neuen Tab im Windows Terminal mit Ubuntu
- Füge folgendes in die Datei
~/.bashrc
mit einem Texteditor ein (z.B. mit nano)
export DOCKER_HOST=tcp://localhost:2375
export DOCKER_BUILDKIT=1
- Prüfe in den Docker-Einstellungen -> Resources -> WSL Integration, dass deine Umgebung aktiv ist.
Windows Subsystem for Linux 1 (WSL 1)
Installiere Docker for Windows (Direktlink) und Git for Windows.
Wenn Du Windows 10 Home verwendest, stelle sicher, dass Du alle Systemanforderungen erfüllst. Dann installiere sowohl Docker Desktop on Windows Home und Git for Windows.
Es ist wichtig, Docker-Zugriff auf C: zu gewähren (in der grafischen Docker-Oberfläche: Einstellungen -> Ressourcen -> Filesharing -> C markieren, anwenden und neu starten).
Du kannst deinen in der Kommando-Shell (z.B. cmd oder powershell) mit dem Befehl docker --version
testen. Wenn es etwas anzeigt, kannst du loslegen.
Starte jetzt dein Windows neu.
Es gibt eine grafische Benutzeroberfläche zur Verwaltung des Repos, die für Git-Anfänger empfohlen wird. Aber Du kannst die Git Bash-Shell genau wie unter Linux benutzen, um sie zu klonen:
git clone git@gitlab.com:foodsharing-dev/foodsharing.git foodsharing
Nach diesem Befehl befinden sich Deine Dateien im Ordner ````%UserProfile%\foodsharing```
Um die Container zu starten, verwende die Git Bash-Shell:
cd foodsharing
./scripts/start
Wenn Du das Startskript zum ersten Mal ausführst, was sehr viel Zeit in Anspruch nimmt, musst du wahrscheinlich der Windows-Firewall das OK geben, damit Docker funktioniert.
Bekannte Windows-Fehler
Allgemein
Wenn etwas nicht in Ordnung ist, überprüfe bitte in Deinem Task-Manager unter "Leistung", ob die Virtualisierung aktiviert ist und behebe gegebenenfalls Fehler.
Git-Fehler (bei WSL1)
Wenn Git nicht gut arbeitet, mach bitte folgendes:
cd foodsharing/bin
tr -d '\15' < console > console
Stell sicher, dass du die `Konsole'-Datei nicht committest und besprich vielleicht weitere Schritte mit dem Team.
[RuntimeException]
Wenn du eine [RuntimeException]
, bekommst, lass ./scripts/start
noch einmal und wieder und wieder laufen, bis alles fertig ist.
yarn lint
Es gibt einen bekannten Fehler bezüglich yarn, siehe: https://github.com/yarnpkg/yarn/issues/7187 and https://github.com/yarnpkg/yarn/issues/7732 und https://github.com/yarnpkg/yarn/issues/7551
Veränderungen in js, vue etc. erscheinen nicht
Damit der webpack-dev-server Änderungen erkennt, musst du diesen watchOptions-Block zu client/serve.config.js
hinzufügen:
[...]
module.exports = {
[...]
devServer: {
watchOptions: {
poll: true
},
[...]
Hinweis: Bitte achte darauf, diese Datei nicht nachträglich mit Ihren Änderungen zu übertragen.
Vagrant
Wenn Du keine der oben genannten Methoden verwenden kannst, dann sollte dies mit jedem gängigen Betriebssystem funktionieren. Allerdings sind wir mit dieser Lösung weniger vertraut, so dass wir Dich damit möglicherweise weniger gut unterstützen können:
Installiere VirtualBox und Vagrant.
Dann:
git clone git@gitlab.com:foodsharing-dev/foodsharing.git foodsharing
cd foodsharing
vagrant up
Für's Tägliche Arbeiten
vagrant up
startet die Maschine und das Foodsharing-Projekt.
vagrant halt
stoppt die virtuelle Maschine.
vagrant ssh
verbindet sich mit der virtuellen Maschine.
Sobald die Verbindung mit der virtuellen Maschine hergestellt ist, gehe mit cd /vagrant
nach /vagrant.
Dort wird der Foodsharing-Ordner in der VM gemountet.
Von dort aus kannst Du alle Skripte mit ./scripts/NAME
ausführen.
Notiz:
./Skripte/Start
wird immer ausgeführt, wenn Du die virtuelle Maschine mit vagrant up
startest.
Es gibt einen bekannten Fehler beim Ausführen von VirtualBox + nginx, dass nginx Dateien aus einem Speicher-Cache bedient. Wenn Du auf dieses Problem stößt, dann kann es wahrscheinlich behoben werden, indem Du den Speicher-Cache mit
sync; sudo sh -c "/bin/echo 3 > /proc/sys/vm/drop_caches"
or even running this every second with watch -n 1 'sync; sudo sh -c "/bin/echo 3 > /proc/sys/vm/drop_caches"'
ausführst.
Getting & running the code
Unten gibt es eine deutsche Übersetzung.
We use the version control system Git and the code is hosted on GitLab. We are open source so you can just clone the repository and start exploring.
For Git, we recommend to use SSH (and the following documentation is supposing that you do so). See e.g. this documentation if you need to configure GitLab for this.
For first use of Git search for tutorials, there are a lot good ones out there.
For exploring the project, check Setting things up afterwards as well and make sure that you followed the Tools installation already. For contributing like writing issues and creating merge requests, check out the Contributing section, and join our mentioned Slack channel (slackin.yunity.org , channel #foodsharing-dev).
Get the code
Get the source code:
git clone git@gitlab.com:foodsharing-dev/foodsharing.git foodsharing
Start the containers
Switch into the source code directory and start the containers:
cd foodsharing
./scripts/start
After running the code for the first time, when visiting the local website, you might get an error like Unable to write to the "/app/var/cache/dev" directory
. Stopping (./scripts/stop
) and re-running (./scripts/start
) the code should fix the problem. Otherwise, check the Troubleshooting.
Den Code ausführen
Wir verwenden das Versionskontrollsystem Git und der Code wird auf GitLab gehostet. Wir sind Open Source, so dass Du das Repository einfach klonen und mit der Erkundung beginnen kannst.
Für Git empfehlen wir die Verwendung von SSH (das Secure Shell Netzwerkprotokoll, die folgende Dokumentation setzt das voraus). Wenn du GitLab dafür konfigurieren musst, hilft vermutlich diese Dokumentation (en).
Für die erste Benutzung von Git such online nach einem Tutorial. Es gibt eine Menge gute Anleitungen.
Um das Projekt zu erkunden, schaue dir danach Setting things up an und stelle sicher, dass du die Installation der nötigen Software bereits abgeschlossen hast. Für Beiträge wie das Schreiben von issues und das Erstellen von Merge-Requests schau in den Abschnitt Einführung in Git und unser Arbeiten an, und komm in unseren Slack-Kanal (slackin.yunity.org , Kanal #foodsharing-dev).
Den Code bekommen
Klone das Repository:
git clone git@gitlab.com:foodsharing-dev/foodsharing.git foodsharing
Die Container starten
Wechsel in das gerade geklonte Verzeichnis und starte die Container:
cd foodsharing
./scripts/start
Wenn du den Code zum ersten Mal ausführst und die lokale Website öffnest, bekommst du möglicherweise einen Fehler wie Unable to write to the "/app/var/cache/dev" directory
. Ein Stoppen (./scripts/stop
) und Neustarten (./scripts/start
) des Codes sollte das Problem beheben. Falls nicht, schau in das Problemlösungskapitel.
Setting things up
You must have completed the installation setup before doing this.
Now go and visit localhost:18080 in your browser. You should see a foodsharing instance running on your local machine :)
For generating a bit of initial data to play with, execute the seeding script:
./scripts/seed
It will give you some users that you can log in with:
Password | Role | |
---|---|---|
user1@example.com | user | Foodsharer |
user2@example.com | user | Foodsaver |
storemanager1@example.com | user | Store manager |
storemanager2@example.com | user | Store manager |
userbot@example.com | user | Ambassador |
userbot2@example.com | user | Ambassador |
userbotreg2@example.com | user | Ambassador |
userorga@example.com | user | Orgateam |
Users with workgroup functionality in the region
Password | workgroup function | |
---|---|---|
userwelcome1@example.com | user | Welcome |
userwelcome2@example.com | user | Welcome |
userwelcome3@example.com | user | Welcome |
userwelcome4@example.com | user | Welcome |
uservoting1@example.com | user | Voting |
uservoting2@example.com | user | Voting |
uservoting3@example.com | user | Voting |
uservoting4@example.com | user | Voting |
userfsp1@example.com | user | foodshare point |
userfsp2@example.com | user | foodshare point |
userstorecoordination1@example.com | user | Store coordination |
userstorecoordination2@example.com | user | Store coordination |
userstorecoordination3@example.com | user | Store coordination |
userreport1@example.com | user | Report |
userreport2@example.com | user | Report |
userreport3@example.com | user | Report |
usermediation1@example.com | user | Mediation |
usermediation2@example.com | user | Mediation |
usermediation3@example.com | user | Mediation |
userarbitration1@example.com | user | Arbitration |
userarbitration2@example.com | user | Arbitration |
userarbitration3@example.com | user | Arbitration |
userarbitration4@example.com | user | Arbitration |
userfsmanagement1@example.com | user | FSManagement |
userfsmanagement2@example.com | user | FSManagement |
userfsmanagement3@example.com | user | FSManagement |
userpr1@example.com | user | PR |
userpr2@example.com | user | PR |
userpr3@example.com | user | PR |
userpr4@example.com | user | PR |
userpr5@example.com | user | PR |
usermoderation1@example.com | user | Moderation |
usermoderation2@example.com | user | Moderation |
usermoderation3@example.com | user | Moderation |
usermoderation4@example.com | user | Moderation |
Some users have additional permissions by being admins of global working groups:
Password | workgroup function | |
---|---|---|
storemanager2@example.com | user | Support |
Please refer to the User Roles and Permissions section for details on the different roles.
Tip: You can use private browser windows to log in with multiple users at the same time!
The script also generates more dummy users and dummy data to fill the page with life (a bit at least).
Should you want to modify it, have a look at the file /src/Dev/SeedCommand.php
.
Whenever you make changes to non-PHP frontend files (e.g. .vue, .js or .scss files), those are directly reflected in the running docker instance. Changes to PHP files will require a page reload in your browser.
To stop everything again, just run:
./scripts/stop
PHPMyAdmin is also included: localhost:18081. Log in with:
Field | Value |
---|---|
Server | db |
Username | root |
Password | root |
There you can directly look at and manipulate the data in the database which can be necessary or very useful for manual testing and troubleshooting.
MailDev is also included: localhost:18084. There you can read all e-mails that you write via the front end.
php Code style
We use php-cs-fixer to format the code style. The aim is to make it use the same style as phpstorm does by default. The fixer is based on the @Symfony ruleset, with a few changes.
To format all files, you can run:
vendor/bin/php-cs-fixer fix --show-progress=estimating --verbose
For convenience, you can and should add the code style fix as a pre-commit hook. So you will never commit/push any PHP code that does not follow the code style rules.
There are two possibilities:
- Using local PHP
- Using Docker PHP
- Using your IDE:
Using local PHP
When PHP >= 7.0 is installed locally and the vendor folder is in place (by having used the automated tests or the dev environment), you can use your computers PHP to check/fix the codestyle, as this is the fastest option:
./scripts/fix-codestyle-local
Adding this to .git/hooks/pre-commit
could look like that:
#!/bin/sh
HASH_BEFORE=$(git diff | sha1sum)
./scripts/fix-codestyle-local
# or use
# vendor/bin/php-cs-fixer fix --show-progress=estimating --verbose
# or
# ./scripts/fix
# if the -local script throws an error
HASH_AFTER=$(git diff | sha1sum)
if test "$HASH_AFTER" != "$HASH_BEFORE" ; then
echo "PHP Codestyle was fixed. Please read the changes and retry commit."
exit 1;
fi
Using docker PHP
Executing the following script will use the dev environment to run the codestyle check. As it currently always runs a new container using docker-compose, it will take some seconds to execute:
./scripts/fix
Using PHPstorm
If you happen to use PHPstorm you can add php-cs-fixer
to those settings as well:


Using VSCode
You can use the php cs fixer Extension. It should work right after a restart. To fix a file right click on it and select

You can even configure it to fix your code style after saving a file under: Settings>PHP CS Fixer>Execute PHP CS Fixer on save for not commiting any non-fixed code.
Note: You need PHP installed locally for this.
Editorconfig
Depending on your editor you need to do nothing or install or configure a plugin to use the file .editorconfig
. Please refer to the section about Code style.
php Code style
We use php-cs-fixer to format the code style. The aim is to make it use the same style as phpstorm does by default. The fixer is based on the @Symfony ruleset, with a few changes.
To format all files, you can run:
vendor/bin/php-cs-fixer fix --show-progress=estimating --verbose
For convenience, you can and should add the code style fix as a pre-commit hook. So you will never commit/push any PHP code that does not follow the code style rules.
There are two possibilities:
- Using local PHP
- Using Docker PHP
- Using your IDE:
Using local PHP
When PHP >= 7.0 is installed locally and the vendor folder is in place (by having used the automated tests or the dev environment), you can use your computers PHP to check/fix the codestyle, as this is the fastest option:
./scripts/fix-codestyle-local
Adding this to .git/hooks/pre-commit
could look like that:
#!/bin/sh
HASH_BEFORE=$(git diff | sha1sum)
./scripts/fix-codestyle-local
# or use
# vendor/bin/php-cs-fixer fix --show-progress=estimating --verbose
# or
# ./scripts/fix
# if the -local script throws an error
HASH_AFTER=$(git diff | sha1sum)
if test "$HASH_AFTER" != "$HASH_BEFORE" ; then
echo "PHP Codestyle was fixed. Please read the changes and retry commit."
exit 1;
fi
Using docker PHP
Executing the following script will use the dev environment to run the codestyle check. As it currently always runs a new container using docker-compose, it will take some seconds to execute:
./scripts/fix
Using PHPstorm
If you happen to use PHPstorm you can add php-cs-fixer
to those settings as well:


Using VSCode
You can use the php cs fixer Extension. It should work right after a restart. To fix a file right click on it and select

You can even configure it to fix your code style after saving a file under: Settings>PHP CS Fixer>Execute PHP CS Fixer on save for not commiting any non-fixed code.
Note: You need PHP installed locally for this.
Editorconfig
Depending on your editor you need to do nothing or install or configure a plugin to use the file .editorconfig
. Please refer to the section about Code style.
Roles and Permissions
After setting up a local foodsharing instance, you will get to know many workflows and actions that are not available to you on foodsharing itself, due to limited roles and permissions.
With access to both the seed data and the database, those limitations no longer exist! Go and play around with some of the local users, or keep reading for a brief overview and explanation.
Roles
Users have a "quiz role" which signifies the level to which they can help manage the foodsharing platform. The most prominent promotion steps are
- from Foodsharer to Foodsaver (the "Foodsaver-Quiz"), which eventually allows you to pick up food in cooperating stores
- from Foodsaver to Store Manager (the "Betriebsverantwortlichen-Quiz"), which enables you to become responsible for cooperations
- from Store Manager to Ambassador (the "Botschafter*innen-Quiz"), which enables you to become ambassador for regions (districts)
In addition to the above, there are also a few select users with global Orga permissions.
Foodsharer
A Foodsharer can
- offer food baskets food baskets on the platform or pick them up
- post information to foodsharepoints (e.g. about current content)
- join or participate in events
- see some personal data for other users (pickup count, forum posts, public info, regions & workgroups, wall)
- edit their own profile and optionally include their address
- chat with other users and become buddies with them (Ich kenne)
- receive trust bananas, but not give them
- receive newsletter mail
- remove their own account
One becomes Foodsharer simply by creating an account on foodsharing.de or foodsharing.at or ... (depending upon country). A foodsharer can not view or interact with stores. They also cannot join a region, so interacting with the forums is not possible.
Foodsaver
A Foodsaver can
- join and leave regions (the nightly script makes sure to also add them to parent regions)
- see stores and apply for membership in a store team, if the team is looking for help
- sign up to fetch food from stores with empty slots, and sign themself out of future pickup slots
- create events in regions or workgroups they are part of
- apply for workgroups and participate
(in theory they could even administrate the group without having the Store Manager Quiz) - view and write in the forum, react to forum posts (large region forums on our platform are moderated)
- generate their personal business card (once verified), not to be confused with their passport
- be asked to manage any foodsharepoint in regions which they are part of
- give and receive trust bananas
- do a lot more that's not listed here :)
Foodsavers have:
- passed the quiz for Foodsaver
- signed the legal agreement
- correct data (which is verified by the BOT via foodsaver ID)
- had some introductory pick-ups (once verified)
- a foodsharing passport (once verified, or soon after)
Store Manager
- can be asked to manage any stores in regions which they are part of
- has accepted the privacy notice regarding sensitive user data (Vertraulichkeitserklärung)
The following assumes the user is store manager for at least one store, although you can of course have passed the Store Manager Quiz and not be managing any store at the moment.
- is displayed at the top of "their" store-team list, for people to contact
- can add and remove store team members, can accept and reject store-team applications
- can move people to and from waiting list, chat with waiting list
- can edit the store properties, team status and what's displayed on the foodsharing map
- can edit the pickup times (repeated ones and one-time pickups)
- can confirm and reject pickup slots
- can see the pickup history (past slots)
Ambassador
The following assumes the user is ambassador for at least one region, although you can of course have passed the Ambassador Quiz and not be acting Ambassador at the moment.
- can manage the profiles of foodsharers and foodsavers with that region as home region (Stammbezirk)
- can manage the foodsaver passports of people from that region
- are displayed in the left sidebar of "their" region's forums, for people to contact
- can perform store manager actions on any stores in that region
- can manage any local workgroup in the region
Orgateam
- basically allowed to see and do anything, but remember: with great power comes great responsibility ;-)
- just browse the pages in the gear-icon menu entry and discover e.g. the internal content management system
Permissions
There are many different things you might manage, for example...
- a workgroup
- a store
- an event
- a foodsharepoint
- a region
- a foodsaver profile
- a newsletter
- a poll
- a foodsaver passport (Ausweis)
- a blogpost
- a food basket
- content in the internal CMS
- quiz questions
In each of those situations (and there are more!) you'll be allowed or not allowed to perform actions based on the permissions for this context. Hopefully over time, we can briefly outline what's what and which things to look out for!
Many of the computations have already been extracted, and you can find them as part of a Permissions class for the respective module. In several other cases though, the checks for what you are and aren't allowed to do are implicit, meaning they are implemented inline throughout the code. We're trying to extract them wherever possible when working on code nearby, and only introduce "clean" permission handling in new code.
Recently, we have also started introducing special workgroups which can take over certain predefined duties that previously belonged to ambassadors only (or did not exist separately at all).
This has been done with the project GOALS (goals@foodsharing.network).
It is possible to assign a workgroup function that grants certain administrative optimised to the function task. The workgroup function affect the district, that the workgroup is appended to.
workgroup-Function | description |
---|---|
Welcome | administrators get a bell about entries of foodsavers into the district |
FSP (foodsharepoint) | managing foodshare points of this region (regardless of who's listed as responsible for the point) |
Store Coordination | managing all stores from this region. If a store coordination group is set up it is prioritized over ambassadors |
Report | managing reports for a region. Technical support for making reports |
Mediation | e-mail address is shown if requesting a mediation |
Arbitration | managing reports with reports of report team |
FSManagement | managing foodsaver in a region (work in progress) |
PR | no special functionality |
Moderation | managing moderation of a district (activate threads). If a moderation group is set up it is prioritized over ambassadors |
Those groups are optional and are set up by writing to the "AG Creation" group. They do show up in the forum sidebar, similar to the ambassador list.
Information on the app setup and others: useful links
If you join the Android Repo, you will find all information on the setup there for development setup instructions on Ubuntu based OSes: refer to /docs/dev-setup-ubuntu.md . (Not in this repository) It is always good to read the Readme-File for the android project.
There is also a Readme-File for the iOS-Project , and a Readme-File for the webpage
If you want to dive deeper into the infos earlier developers have hidden throughout the project, you'll find here information on the homepage (like a flyer and a list of responsibilities).
back to the main page
Einführung in Git und unser Arbeiten
English short version of this file: Making and submitting changes
Was du hier findest:
- Wie du unserem Projekt beitrittst
- Wie du einen Starter Task findest
- Tutorials
- Auf welchen Ebenen Git funktioniert
- Workflow
- Was es zum Merge Request zu sagen gibt
- Wie du einen Rebase machst
- Wie du mit Rebase-Konflikten in unseren Abhängigkeiten umgehst
- Merge in den Master
- Ein Issue anlegen
- Testen
Wie du unserem Projekt beitrittst
In der foodsharing-IT organisieren wir unsere Arbeit über Slack (https://slackin.yunity.org).
Dafür musst du dir ein Konto bei Slack mit einer funktionierenden E-Mail-Adresse anlegen.
Im Kanal #foodsharing-dev
(auf https://slackin.yunity.org) besprechen wir, was zu tun ist.
Sag da am besten auf Englisch Hallo und stell dich dem Team vor - mit deinen Skills und woran du gern arbeiten würdest.
Der gesamte Code liegt im Repository unter https://gitlab.com/foodsharing-dev/foodsharing.
Da gibt es neben der "Project ID: 1454647" die Möglichkeit, auf Request Access
zu klicken.
Sag uns in yunity Slack im Kanal #foodsharing-dev
Bescheid und wir geben dir die Bearbeitungsrechte.
Als Mitglied auf GitLab kannst du:
- Branches innerhalb des Repository erstellen und verschieben (außer Master, mehr zu Branches unten)
- Vertrauliche Issues sehen
- Labels vergeben (supernützlich!)
- Dich Issues zuordnen (um anderen zu sagen, dass sie nicht damit anfangen müssen)
Zum Mitarbeiten brauchst du dann noch deine lokale Programmierumgebung.
Wie du einen Starter Task findest
Mit welcher Aufgabe du anfangen könntest, hängt natürlich von deinen Vorkenntnissen ab. Frag am besten in Slack nach, was ein guter Starter Task wäre.
Du kannst dir auch selbst etwas aussuchen unter https://gitlab.com/foodsharing-dev/foodsharing/-/issues?label_name%5B%5D=Starter+task
Ordne dich bitte dem Issue zu, das du bearbeitest. (Rechts oben im Issue: assign yourself
)
Tutorials
Tutorial-Empfehlungen für den Umgang mit Git:
- Für die Basics: http://rogerdudler.github.io/git-guide/
- Für Rebase etc.: http://think-like-a-git.net, https://git-scm.com/doc und https://learngitbranching.js.org/
Auf welchen Ebenen Git funktioniert
1. Ebene: Deine Arbeitsumgebung. Wenn du Sachen änderst, wird erstmal nichts hochgeladen. Sobald du anfängst, Änderungen zu schreiben, empfiehlt es sich, einen Branch zu erstellen. Wie bei einem Baum ist der Zweig etwas, was von dem Stamm abgeht. Alle haben den Master (Baum), aber erstmal hast nur du deinen Zweig (Branch). https://confluence.atlassian.com/bitbucket/branching-a-repository-223217999.html
2. Ebene: Du möchtest, dass auch andere deinen Branch sehen und darüber philosophieren können. Dafür musst du deine Änderungen bestätigen, to commit. Damit hebst du die Dateien einzeln auf die Upload-Ebene. Sobald du anfängst, zu committen, lohnt es sich einen Merge Request zu erstellen. Den Merge Request erstellst du im GitLab selbst: https://gitlab.com/foodsharing-dev/foodsharing/-/merge_requests/new Der MR sagt aus: "Ich arbeite daran und werde in absehbarer Zeit fertig". Solange es noch ein Work in Progress ist, solltest du den MR mit 'Draft: ' am Anfang benennen. Sobald der MR fertig ist, benennst du ihn um, bittest im Kanal um ein review, und wenn jemand gesagt hat: Yo, läuft, dann kann der Merge Request gemerged werden, also mit dem Master zusammengeführt werden. Dafür musst du in der Regel erst deinen Zweig lokal mit dem Master zusammenführen: rebase. Wenn ein MR übernommen ist, hat dein Code die 3. Ebene erreicht und alle, die sich das Repository ziehen, haben ihn ebenfalls im Master.
3. Ebene ist dann, wenn von der Test/Beta-Version in die produktive Version rübergeschaufelt wird. Wenn du Probleme hast, frag am besten jemand im Kanal, ob er/sie dir helfen kann, die Git-Kommandos in der richtigen Reihenfolge auszuführen.
Workflow
Ein Workflow kann so aussehen: TL/DR: Branch erstellen -> ein oder mehrere commits machen -> pushen -> MR erstellen
git checkout master
git pull
git checkout -b 123-fix-for-issue-123
(Erstellt den Branch 123-fix-for-issue-123. Es ist gut, wenn du die Issue-Zahl vorne an deinen Branch setzt, damit wir sehen können, wozu er gehört. Du kannst gerne genauer beschreiben, worum es geht: git checkout -b 812-1-make-devdocs-contributing-a-german-text
)
Anschließend an Dateien arbeiten.
git add src/EditedFile.php
(Fügt die bearbeitete Datei src/EditedFile.php
zu denen hinzu, die hochgeladen werden sollen. Es ist empfehlenswert, git add -p path_to_file
zu benutzen, damit du genau weißt, was du zum Commit hinzufügst.)
git status
ODER
git diff --staged
(Nützlich, um sich vor dem commit anzuschauen was gerade der Status ist oder was man gerade in seiner staging area hat und was genau zu dem aktuellen commit hinzugefügt wird)
./scripts/fix-codestyle-local
(oder, wenn das nicht funktioniert, benutz das langsamere ./scripts/fix
)
Damit überprüfst du deinen Code style.
./scripts/test
Damit lässt du lokal die Tests durchlaufen.
Für spätere Wiederholungstests nutze: ./scripts/test-rerun
(viel schneller!)
git commit -m "Changed something in EditedFile.php"
git push --set-upstream origin 123-fix-for-issue-123
(Bündelt die Änderungen mit der öffentlichen Notiz "..." und lädt sie hoch. Es kann sein, dass ein Kommando vorschlägt, das noch zu geben ist. Insbesondere bietet es sich hier an, einen MR für den Branch zu erstellen und ihn als Draft zu markieren.)
Anschließend weiterarbeiten
git add src/AnotherFile.php
git commit -m "Changed something in AnotherFile.php"
git push
// Jetzt funktioniert es //
Wenn du das Changelog bearbeitet hast:
git add CHANGELOG.md
git commit -m "Updated Changelog"
git push
(Nach git push
kann man als Kommando -o ci.skip
hinzufügen. Das überspringt Tests, was etwas Energie spart. Tests sind am Ende allerdings wichtig, wenn alle Dateien fertig sind.)
Wenn du fertig bist:
git checkout master
git pull
git checkout 123-fix-for-issue-123
git rebase master
// Bezogen darauf, wie alt dein Branch und andere Änderungen sind, wird dies wahlweise direkt funktionieren oder mehr Arbeit erfordern. Folge einfach den Anweisungen von git.
git push -f
// Ein "force push" wird deine Änderungen an der Quelle überschreiben, da der Rebase den Verlauf deines Branch verändert hat
Was es zum Merge Request zu sagen gibt
Je übersichtlicher und besser beschrieben der Merge Request (MR) ist, desto einfach ist es für andere, ihn zu reviewen. Das heißt:
-
Gib dem MR einen aussagekräftigen Namen
-
Verwende bitte ein Template für die Beschreibung (
Default
aus der dropdown-Liste) und beschreibe, was die Änderung macht. -
Wenn es eine Änderung an der UI ist, füg gerne auch ein paar Screenshots ein.
-
Geh einmal die Checklist (ganz unten im Template) durch und schau, ob du alle Punkte beachtet hast, bzw. Punkte nicht zutreffen. Beispielsweise ist nicht immer ein Test notwendig oder möglich. Die Ausnahme ist der letzte Punkt ("Once your MR has been merged...") der das Testen nach dem mergen betrifft (s.u.)
-
Gib dem MR noch ein paar Label, die ihn einordnen. Insbesondere ein "state"-Label hilft zu sehen, ob der MR fertig ist.
Unten im MR kann dieser diskutiert werden. Anmerkungen am Code kannst du am besten unter "Changes" direkt an der entsprechenden Zeile einfügen.
Wie du einen Rebase machst
-
Du holst dir mit
git checkout master
undgit pull
die aktuellen Änderungen vom master Branch. -
Wechsele danach wieder mit
git checkout BRANCHNAME
in deinen branch. -
git rebase master
ist der Befehl deiner Wahl. (Den Unterschied zwischen rebase und merge findest du hier: https://git-scm.com/book/en/v2/Git-Branching-Rebasing) Falls du das Programm phpstorm nutzt, klickst du rechts unten auf deinen Branchnamen. Dadurch geht ein Menü auf, in dem du den Master auswählst und anklickst: "checkout and rebase onto current". -
Sollte das rebasen zu kompliziert sein oder nicht funktionieren: Fallen lassen wie eine heiße Kartoffel ;-) mit dem Befehl
git rebase --abort
Führe stattdessen ein merge durch, da dies einfacher ist, da nur die Änderungen von master branch eingefügt werden. Hierzu kannst du den Befehlgit merge master
anwenden. In phpstorm gibt es zwei Menüpunkte unter dem obigen: "Merge into current". Du findest unten rechts eine Möglichkeit, dir die Versionsunterschiede anzeigen zu lassen. Mit dem Zauberstab-Knopf oben kannst du konfliktfreie Änderungen automatisch vornehmen lassen. "ours" und "theirs" entspricht den Pfeilen am Diff-Rand. (... Hier könnte jemand irgendwann Screenshots einfügen ...) -
Danach kannst du mit einem
git commit
undgit push
die Änderungen hochladen, wenn du alle Konflikte bereinigt bekommst.
Wie du mit Rebase-Konflikten in unseren Abhängigkeiten umgehst
Hast du in deinem Branch Änderungen an der composer.json
und / oder client/packages.json
durchgeführt und gleichzeitig hat jemand auch an diesen Dateien Änderungen in den master gemergt, kommt es in composer.lock
und yarn.lock
zu einem Konflikt.
-
Führe den Befehl
git checkout master -- chat/yarn.lock, client/yarn.lock or composer.lock
aus -
Danach loggst du Dich mit
./scripts/docker-compose run --rm client sh
in den Docker-Container "Client" ein. -
Führe darin den Befehl
yarn
aus und beende mitexit
, wenn dieser fertig ist. (bzw. für composer wäre es./scripts/composer install
) -
Danach kannst du mit einem
git add chat/yarn.lock, client/yarn.lock or composer.lock
undgit rebase --continue
den Rebase fortsetzen.
(Auf der Rebase-Seite gibt es auch ein Beispiel)
Merge in den Master
Wenn du fertig bist, meldest du dich im Slack-Dev-Kanal und schreibst da einen Link zu deinem MR hin, mit der bitte um Rückmeldungen. Andere Devs werden sich dann mit Feedback oder Änderungswünschen an Dich wenden. Bitte habe etwas Geduld, wenn das nicht sofort passiert.
Sobald der/die Genehmigende deinen MR für fertig befindet, wird er ihn in den Master übernehmen.
Der Master-Zweig wird automatisch auf beta.foodsharing.de bereitgestellt, wo er getestet werden kann. In der Arbeitsgruppe Beta Testing auf foodsharing.de solltest du jetzt im Forum einen Beitrag für ein Testszenario erstellen, so dass es von anderen ausführlich getestet werden kann. Der Beitrag sollte das Format haben:
- Titel:
- Test-Aufgabe: Problem in einem Satz
- Nachricht:
- Was ist das Problem?
- Wie kann man das Problem Schritt-für-Schritt reproduzieren?
- Was ist der Soll-Zustand?
- Deadline (Zeitpunkt, bis zu dem das Testen erledigt sein sollte)
Dort gibt es dann noch einmal gegebenenfalls Rückmeldungen zu Fehlermeldungen. (Besser hier als auf foodsharing.de! :-) )
... für einen Überblick über verschiedene Umgebungen: Environments on GitLab
Am Ende werden die beta-Änderungen auf die Produktiv-Seite übernommen - und dein MR ist abgehakt.
Und dann ... Zeit für eine neue Aufgabe ...?
Wenn du eine Frage hast, erreichst du uns über yunity Slack: komm in den Kanal #foodsharing-dev
.
Ein Issue anlegen
Wenn dir etwas an der foodsharing-Webseite aufgefallen ist: prüf bitte, ob das auf beta.foodsharing.de und www.foodsharing.de auftaucht.
-
www und beta = es ist ein unbearbeitetes Verhalten = prüf bitte, ob das Issue bereits bei GitLab eingetragen ist: https://gitlab.com/foodsharing-dev/foodsharing/issues ... wenn es noch nicht existiert: leg das issue bitte mit möglichst genauen Informationen an
-
www und nicht beta = wir haben uns schon drum gekümmert
-
nicht www aber beta = wir haben es verursacht = bitte im Slack-Beta-Kanal melden
Testen
Du kannst die Tests mit ./scripts/test
bzw. ./scripts/test-rerun
durchführen (siehe oben).
Solange wir die Tests so schreiben, dass sie idempotent ablaufen, nutz bitte test-rerun!
Bis jetzt funktionieren die Ende-zu-Ende-Tests (in der Codeception acceptance test genannt) gut. Sie laufen mit einem kopflosen Firefox und Selenium innerhalb des Dockers und sie werden auch auf CI-Basis ausgeführt.
Wir sind dabei, den Code umzustrukturieren, um Unit-Tests zu ermöglichen: https://gitlab.com/foodsharing-dev/foodsharing/issues/68
Der während des Testens erzeugte Zustand wird nicht weggeworfen, und du kannst die Test-App nutzen: Im Browser: http://localhost:28080/ und es hat seinen eigenen phpmyadmin: http://localhost:28081/
Wenn du die Tests mit eingeschaltetem Debug-Modus durchführen willst, verwende ./scripts/test --debug
.
Wenn du nur einen Test ausführen willst, gib den Pfad zu diesem Test als Argument an, z.B: ./scripts/test tests/acceptance/LoginCept.php
.
Ausführlicheres zu Tests findest du hier.
Making and submitting changes
Deutsche lange Version dieser Datei: Einführung in Git und unser Arbeiten
What you'll find here:
General
If you have any questions please reach out to us via slack: https://slackin.yunity.org/ and join the #foodsharing-dev
channel.
Submitting an issue
If you found an issue on the foodsharing website, then please submit it to our GitLab issues: https://gitlab.com/foodsharing-dev/foodsharing/issues
If you feel comfortable submitting a fix or if you would like to try and learn by doing and other team members in the process, follow the next section.
Submitting a change
Becoming a member
As a “member” on our versioning system GitLab you can
-
create and push to branches within the repository (except master).
-
see confidential issues.
-
set labels to issues.
-
assign yourself to issues (to tell others that they do not need to start on them).
After creating a GitLab account and applying for membership, write a few introducing lines about yourself on the Slack channel https://slackin.yunity.org/ #foodsharing-dev
.
You can apply for membership by clicking the Request Access button in the GitLab UI https://gitlab.com/foodsharing-dev/foodsharing after you created your account.
Working on an issue
You can either submit your own issue and work on it or work on existing issues. Issues that are suitable for newcomers are labeled as starter tasks: https://gitlab.com/foodsharing-dev/foodsharing/issues?label_name%5B%5D=starter+task
One-Time-Setup:
-
Create a GitLab account https://gitlab.com/users/sign_up or use an existing account.
-
Create a SSH key, e.g. via terminal command
ssh-keygen -t ed25519 -C "my@email.com"
. Then, as a name, enterfoodsharing_ssh_key
, for example. A passphrase is optional. -
Upload the generated key to your GitLab user profile keys https://gitlab.com/-/profile/keys as a new entry to authenticate your computer to the foodsharing GitLab via SSH.
-
Install Git: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
-
Clone the git repository by executing:
git clone git@gitlab.com:foodsharing-dev/foodsharing.git
To make a desired change, please work on your own branch named after the issue number (skip the following paragraph, if you already know how to use Git & collaborate in GitLab):
-
Check if an existing issue has already been created for the change in the public GitLab issue backlog: https://gitlab.com/foodsharing-dev/foodsharing/issues
-
Hint: If you are just submitting a very small change or a doc fix, then don't worry about creating an issue. If you find an issue, only work on it if there is no assignee yet in the issue details bar at the right. If there is an assignee, someone else is already working on the ticket. For a bigger change, discuss if you can help out or split the work into sub-tasks.
-
Click the "assign yourself" button in the right bar of the issue to indicate that you started working on the issue.
-
-
Update to the newest changes on master branch by executing
git checkout master
andgit pull
. -
Create a new local git branch for your local changes, prefixed with the issue number, by executing the command
git checkout -b <issue-id><your-name (optional)><some-descriptive-words>
.-
For example, the issue number
56
could have a branch named56-nick-sellen-some-descriptive-words
. -
Hint: Best practice is to work in your own branch and never in the master branch. You can create more than one branch at once to work on different issues simultaneously.
-
-
Make your changes and push them via the following commands.
4.1.
git status
to see which files changed.4.2.
git add <desired files>
(git add .
will add all changed files to version control.),4.3.
git commit -m "<description of change>"
andgit push -u origin HEAD
initially to set the upstream name equal to the branch name you created locally.4.4. If your changes are very small or only about documentation, you can consider using the push option
git push -o ci.skip
which disables running the build and test on the Gitlab server.
To submit your change:
-
Check if the code style is fixed before commiting, by running
./scripts/fix-codestyle-local
(or if that does not work by running the slower./scripts/fix
). -
Check if the tests pass locally, by running
./scripts/test
. -
Create a merge request to master for your branch early on.
3.1. Select the template "Default".
3.2. Prefix the name of the merge request with
Draft:
. -
Make sure your merge request checks all the checkboxes in the "Default" template (and check them in the description).
-
Once you think your branch is ready to be merged, remove the
Draft:
prefix from the name of your merge request. Rebase your branch onto master (which might have developed since your branching). It is OK to force-push (git push origin <your_branch_name> -f
) after rebasing. -
Submit your merge request.
The next steps will be:
-
An approver will get back to you with feedback or change requests. Please have some patience if this does not happen right away.
-
Once the approver considers your changeset ready to be made, they will merge it into the master branch.
-
The newest version of the master branch will be deployed automatically to https://beta.foodsharing.de/ after some time, where you can try it out (uses production database).
- See https://gitlab.com/foodsharing-dev/foodsharing/environments for an overview of the different environments.
-
After your MR has been merged, you are responsible to create a testing issue in the Beta Testing forum: https://foodsharing.de/?page=bezirk&bid=734&sub=forum:
- Consider writing a detailed description in German.
- Describe in a few sentences, what should be tested from a user perspective.
- Also mention different settings (e.g. different browsers, roles, ...) how this change can be tested.
- Be aware, that also non technical people should understand.
-
Hang around and see if people in
#foodsharing-dev
on Slack at https://yunity.slack.com/ find any issues, etc. -
At some point in the future, once a few changes have been collected, they will all be deployed to production.
Testing
It is recommended to only run individual tests locally.
To do so, pass the path to that test as an argument to the test script,
e.g.: ./scripts/test tests/acceptance/LoginCept.php
to run only the tests within this test bundle.
You can run a single test by ./scripts/test <path>:<method_name> <parameters>
, e.g. ./scripts/test tests/api/StoreApiCest.php:canWriteStoreWallpostAndGetAllPosts --debug
.
If you want to run the tests with debug mode turned on, use: ./scripts/test --debug
.
You can run all the tests at once with ./scripts/test
locally (a lot of time and good hardware required).
For your second and following runs, you can use ./scripts/test-rerun
which runs much quicker.
(as long as we keep writing the tests to run idempotently, please do!).
So far, end-to-end tests (called acceptance tests in codeception) work nicely. They run with a headless Firefox and Selenium inside the Docker setup and they are run on CI build too.
We are restructuring the code to enable unit testing. Related issue: https://gitlab.com/foodsharing-dev/foodsharing/issues/68
The state created during testing is not thrown away, and you can visit the test app in your browser :http://localhost:28080/ and it has its own phpmyadmin: http://localhost:28081
Frequently asked questions - what you can find here
- The architecture is not clear to me. Could you explain the basic layout?
- How do you start?
- What are our technical constraints? (such as server, storage. memory and communication interfaces)
- Are there visual guidelines? (User interface, colors, buttons, etc.)
- What are the security parameters? (i.e. how the website will ensure secure access control and transactions)
- So if we break the homepage down into its parts - how is it structured?
- What is the relationship between karrot and foodsharing currently?
- it-tasks lists a number of tech stuff we use on the page. How is their relationship to each other / what do we use them for?
- Who can I ask for help with what? Who is part of the team with which focus and which skills? (volunteer list)
Basic layout
Q: The architecture is not clear to me. Could you explain the basic layout?
A: The main architecture goals came from this book "Modernizing Legacy Applications In PHP", although we deviate in some place. There is also a great 1h video describing rough details about what the book is talking about.
A few current architecture goals would be:
- only 1 php entrypoint (
index.php
), remove xhr|xhrapp.php/etc - use symfony approach for handling all requests (some controllers do this already, others use the old way), in IndexController the
$isUsingResponse
switches behaviour based on that - create REST controllers for all API use, remove all other API stuff
- use a symfony router or similar (might also involve changing page urls to nice paths instead of get parameters + adding redirects)
- have simple/general/default kind of symfony
index.php
for templates/frontend stuff - remove all html/js in php strings
- use vue.js for all dynamic kind of templates
- remove global eval stuff ... goes with the only REST API endpoints ...
- modernize a lot more of the frontend code
- replace years long outdated flourish lib
So the preferred approach would be Model to Gateway classes, see here: Issue 9
Getting started
Q: I would really love to do anything, but when I look at the repo I can't even find a thing I could change just for testing! How do you start?
A: One technique is to
- find some text that is clearly visible on the page, and
- search the codebase for it, which might point to a translation string, then
- search for that translation key,
- repeat until finding it.
In foodsharing some of the longer content comes from the database, so you won't find that in the the codebase (except for maybe in an sql seed file), so try things more like buttons, or menu items...
Technical constraints
Q: What are our technical constraints? (such as server, storage. memory and communication interfaces)
A: The server has 32G of memory, currently. Server stats:
The current email load is high, we get spam-flagged a lot, so in the future we need to introduce (more) granular email settings to users. (E-mail handling: we have currently more than one server for mails.) When we use a third party service, we sometimes run into problems (photon, map tiles).
visual guidelines
Q: Are there visual guidelines? (User interface, colors, buttons, etc.)
A: There are guidelines. Basically, we use common sense.
The frontend needs rewriting as well and currently we're mostly working on & refactoring the backend.
... it could look like Karrot
security parameters
Q: What are the security parameters? (i.e. how the website will ensure secure access control and transactions)
A: There were a lot of SQL injections. Now we use prepared statements, which is clearer. Vue helps against XSS attacks. (there might be legacy stuff lurking)
Moving (from XHR to REST APIs made it safer as well.
We're aiming for a point, where you get only the data you're requesting (Currently a lot of code is structured "if you're this or that, you get to see xy")
Structure
Q: So if we break the homepage down into its parts - how is it structured?
A: For some of the php code, see the php page.
Most of our functions can be found in /src/Helpers/
.
Book: https://leanpub.com/mlaphp
We still have some of the functions that bit by bit get replaced during refactoring.
karrot
Q: What is the relationship between karrot and foodsharing currently?
A: karrot enables communities to do foodsaving - foodsharing is basically in german and has a lot of structures that some countries didn't want (thus e.g. minimizing the use of admins in the groups) ... the german-speaking organizational structures are kinda rooted in the code of foodsharing.
foodsharing is ALSO an organization.
karrot is a software project, the people who use it are their own organization, in a way.
Chandi showed how karrot and foodsharing might work together on the code base. (https://yunity.slack.com/archives/C1T1ZM9A4/p1577146381053600) For now, we're focusing on modernizing the codebase.
our tech
Q: it-tasks.html lists a number of tech stuff we use on the page. How is their relationship to each other / what do we use them for? What do we want to remove from our codebase?
A: We use ...
- PHP (Symfony 5) ... we also use a lot of non-symfony-php, that we want to refactor
- JavaScript (Webpack, Vue.js) ... we're also modernizing some old JavaScript. Vue impacts mainly just one thing. CSS mostly has an effect on other stuff as well. (see below)
- HTML (Twig) ... there is also the old way with string contatination. Twig is the new way. We're moving more towards vue.
- CSS (Bootstrap) ... move from global CSS to vuevue components
- MariaDB (which is basically MySQL) currently has a very lax error handling configuration. We try to set a more strict config here.
- Redis is also very low maintenancy. It's a cache, where the session is stored.
- socket.io nodejs server - the chat server. Low maintenance.
- RESTful APIs - We also have old ones but are moving towards REST.
- the Docker Compose development environment
- Codeception for Unit-, API-, and Acceptance testing (with Selenium) -
- Git
- GitLab CI for tests and automatic deployment (with php deployer) - this is a nice, stable setup through which multiple people can deploy stuff. (Not bottle-necking through one person as jobs are usually splitted between at least two servers.)
helping hands
Q: Who can I ask for help with what? Who is part of the team with which focus and which skills? (volunteer list)
A: The common and most efficient way is to ask the dev channel a detailed question - so everyone who might have the knowledge and time can help.
Also we have team members with special responsibilities, see here: https://gitlab.com/foodsharing-dev/foodsharing/-/wikis/responsibilities
This means that there currently is no one head of the foodsharing IT. We decide with votes & vetos. Therefore currently there is no roadmap. The responsibles have lately said, that cleaning up old code and finishing open Merge Requests has priority over new features. But basically if you like an idea and are willing to work on your code - you're welcome to join. :-)
Coding guidelines
We do have a few coding guidelines, mentioned at various places in these devdocs. In general, please use your common sense and make it fit with the existing code.
Code style
Why
First of all, why do we need a code style: If the code looks everywhere the same, it is easier to read and thus to maintain. You are getting kind of a style, a common syntax everybody can understand. You can even distinguish library code from our own code like this. There are also some pedantics who like such a clean overall look. But most important thing is that nobody wants to get reviews saying “too many blank lines”, “please indent by spaces”, “The brace should be on the next line”. In short, no review on anything regarding white space.
Additionally, we do not want to have to review huge amounts of code with such a diff:

if you see this in pure diff style (and are not able to read the matrix without a GUI), this becomes very cumbersome.
Editorconfig
The cool thing is, as we now all love code styling, but everybody hates code style fixing, we do automate all such things.
The file /.editorconfig
(see [https://editorconfig.org/]) specifies our most basic settings on white-spacing which most of your IDEs will be able to follow.
Editorconfig is a file format and collection of text editor plugins for maintaining consistent coding styles between different editors and IDEs.
PHPstorm
In PHPstorm this is how you select it: use the corresponding plugin:

For the editorconfig file format there are super nice inspections in PHPstorm (under Editor-Inspections after searching for editorconfig). Leave them all in. The more annoying, the better.
VSCode

To use EditorConfig, install the official EditorConfig for VSCode Extension. It will automatically use the proper .editorconfig file from the repository.
Testing
Running tests
Run the tests with:
./scripts/test
You will need to have initialized everything once (with ./scripts/start
), but you do not need to have the main containers running to run the tests as it uses it's own cluster of docker containers.
After running the test, you can stop it with FS_ENV=test ./scripts/stop
. If you don't, the docker containers keep running and need resources.
With this, you can set the FS_ENV environment variable to test, so they operate on the test environment.
Also it is possible to add this in the config file. Maybe some day this info gets added. :-)
After you have run the tests once, you can use ./scripts/test-rerun
which will run faster. It assumes that the containers have already been created and initialized, but otherwise is the same.
So far, end to end testing is working nicely (called acceptance tests in codeception). They run with a headless Firefox and Selenium inside the Docker setup, they are run on CI build too.
We are working on restructing the code to enable unit testing.
The test contains stay around after running, and you can visit the test app in your browser, and it has it's own phpmyadmin.
If you want to run with debug mode turned on, then use: ./scripts/test --debug
.
If you just want to run one test, then pass the path to that test as an argument, e.g. ./scripts/test tests/acceptance/LoginCept.php
.
Writing unit tests
CodeCeption uses PHPUnitTests under the hood and therefore the PHPUnit test documentation can be helpful.
Writing acceptance tests
The tests
directory has much stuff in it.
You just need to care about 2 places:
tests/seed.sql
- add any data you want to be in the database when the tests are run
acceptance/
- copy an existing test and get started!
http://codeception.com/docs/modules/WebDriver#Actions is a very useful page, showing all the things can call on$I
.
Please read the command descriptions carefully.
How acceptance tests work
Tests are run through selenium on firefox. The interaction of the test with the browser is defined by commands. Keep in mind that this is on very high level. Selenium does at most points not know what the browser is doing!
It is especially hard to get waits right as the blocking/waiting behaviour of the commands may change with the test driver (PhantomJS, Firefox, Chromium, etc.).
$I->amOnPage
uses WebDriver GET command and waits for the HTML body of the page to be loaded (JavaScript onload handler fired), but nothing else.
$I->click
just fires a click event on the given element. It does not wait for anything afterwards! If you expect a page reload or any asynchronous requests happening, you need to wait for that before being able to assert any content.
Even just a javascript popup, like an alert, may not be visible immediately!
$I->waitForPageBody()
can be used to wait for the static page load to be done. It does also not wait for any javascript executed etc.
HtmlAcceptanceTests
Acceptance tests using the HtmlAcceptanceTester
class are run in PhpBrowser. Those tests run on a lower level then WebDriver. They can only test a page's HTML content. Therefore features like JavaScript are not available, but tests run faster.
From Codeception documentation:
HtmlAcceptanceTester | AcceptanceTester | |
---|---|---|
JavaScript | No | Yes |
see /seeElement checks if text is… | …present in the HTML source | …actually visible to the user |
Speed | Fast | Slow |
Code quality and reviews
The main goal of your contribution to the foodsharing codebase should be to make the platform great for the users. Still, a very important aspect of that is to make the codebase great for developers as well so others can help with making it great for the users. That is why you should have a second goal with each commit: Make the code a little bit nicer than it was before. Below is a list of things that should be kept in mind when touching code but also when reviewing. When you think there is something touched that might break one of the points listed below, better delay the approval of the merge request or ask another person for a review.
What you should care about specifically
If you take responsibility it's okay to break master. Please try not to break it horribly :-D
We welcome new and beginner developers to contribute to foodsharing and understand that part of that might involve accidentally breaking bits of the site. And that is okay, as long as they stick around to fix what they broke. Still, try to be aware of what you are touching:
- Do not break things that affect non-beta users
- Email notifications generated by actions of beta users are send to everybody
- Modification of data, especially in stores, forums and walls, affect everybody as the content is shown on beta and production
- An accidental loss of data is the worst case
Do not introduce security issues again
- Never write any new code using
Foodsharing\Lib\Db
class, always useFoodsharing\Modules\Core\Database
with prepared statements - When refactoring, take one step at a time. A lot of old code uses
strip_tags
as a basic Cross Site Scripting prevention method, it is hidden behindstrval
. Keep it when moving code. - Always be aware what type of data is held in a variable: Plain text, HTML text, markdown? The old code does mostly not do this and is not even aware of the type when outputting it to the user. Still, when you want to change that behaviour, you must be aware of every single instance of that string used over the platform (e.g. it might be stored to the database or session and retrieved at other places). If in doubt, first try to leave that behaviour exactly as you found it and refactor as a separate step
REST API Endpoints
In the issue #511 some rules for creation of REST API Endpoints are formulated. For general explanation about REST, see request types.
- english only
- use "normalizer" methods to transform gateway/db data into api responses
- camel case for keys (
regionId
instead ofregion_id
) - prefixes for booleans (
isPublic
instead ofpublic
) GET
requests should never change data- use Permission classes for permission checks
- never use Model classes
- regions and working groups are both 'groups'
- name keys always as specific as possible (
createdAt
instead oftime
,author
instead ofuser
) - integers should also be send as an integer, not as a string
- Standardize date and time: ISO 8601. Use the
DATE_ATOM
PHP DateTime formatter. - Add a message to exceptions. (e.g.
throw new HttpException(404, 'This region with id ' . $regionId . ' does not exist.');
)
More not-yet-implemented ideas include:
- Add API versioning (to allow introducing breaking api changes in the future without immediately breaking the apps) (not yet, hopefully coming at some point)
- Standardize pagination (e.g. fixed query param names, return total number of items, either via envelope or header)
- Automatically generated documentation for REST API
Documentation
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
Overview
Documentation should be as important to a developer as all other facets of development. Or as Atlassian states it: Documentation should be your best friend. Therefore it is recommended to embrace this attitute going forward.
This document should help you with the basics and guidelines of documentation for this project. For the developer documentation please check out the section about the devdocs.
General
You may always consider using online guides like https://www.markdownguide.org/ or https://guides.github.com/features/mastering-markdown/ (besides GitHub Flavored Markdown for the latter which only works on GitHub.com of course).
Files
All Markdown files MUST have .md
file extension.
All Markdown files MUST use the Unix LF (linefeed) line ending only.
All Markdown files SHOULD end with a non-blank line, terminated with a single LF.
All Markdown files SHOULD be linted. (See Linting)
All Markdown files SHOULD contain a table of contents. (For auto generation check out the editing recommendations.)
Linting
See the general rules of markdownlint. Custom rules are applied using a config file with the name .markdownlint.json.
Using Docker
Editor Extensions
Please see the related to markdownlint section.
Contents
- How you perform a rebase
- How to deal with rebase conflicts in our dependencies
- Rebase on console with an example
How you perform a rebase
- You get the current changes from the master branch using
git checkout master
andgit pull
. - Change back to your branch with
git checkout BRANCHNAME
. git rebase master
is the command of your choice. (You can find the difference between rebase and merge here: https://git-scm.com/book/en/v2/Git-Branching-Rebasing)
If you use the phpstorm program, click on your branch name below. This will bring up a menu where you select the master and click "checkout and rebase onto current".
- if the rebase is too complicated or does not work: Drop it like a hot potato ;-) with the command
"git rebase --abort"
Do a merge instead, as this is easier as only the changes from master branch are inserted. You can use thegit merge master
command for this.
In phpstorm there are two menu items under the above: "Merge into current". You will find a way to see the version differences in the lower right corner. With the magic wand button at the top you can have conflict-free changes made automatically. "ours" and "theirs" correspond to the arrows on the diff border. (... Someone might insert screenshots here at some point...)
- After that you can upload the changes with a
git commit
andgit push
, if you manage to fix all conflicts.
How to deal with rebase conflicts in our dependencies
(https://stackoverrun.com/de/q/11809185)
If you have made changes to composer.json and / or client/packages.json in your branch and at the same time someone has merged changes to these files into the master, a conflict will occur in composer.lock and yarn.lock.
- Execute the command
git checkout master -- chat/yarn.lock
, ...client/yarn.lock
or ...composer.lock
- Then log into the docker container "client" with
./scripts/docker-compose run --rm client sh
. - Execute the command
yarn
and finish withexit
when it is finished. (For composer it would be./scripts/composer install
.) - Then you can continue the rebase with a
git add chat/yarn.lock, client/yarn.lock or composer.lock
andgit rebase --continue
.
Rebase on console with an example
If your rebase in the console looks like this ...
git rebase master
Auto-merging src/Modules/Profile/ProfileView.php
CONFLICT (content): Merge conflict in src/Modules/Profile/ProfileView.php
Auto-merging lang/DE/de.php
Auto-merging lang/DE/Settings.lang.php
error: could not apply 62feb08c3 ... make use of "about_me_public" as described on profile page.
... then resolve all conflicts manually, mark them as resolved with:
"git add/rm <conflicted_files>", then run "git rebase --continue",
You can instead skip this commit: "run git rebase --skip".
To abort and get back to the state before git rebase, run "git rebase --abort".
Could not apply 62feb08c3 ... make use of "about_me_public" as described on profile page
then open the conflicting file with an editor of your choice. It will have the HEAD marker somewhat like this:
<<<<<<< HEAD
=======
/**
* @param array $infos
*
* @return array
*/
private function renderAboutMePublicInformation(array $infos): array
{
if ($this->foodsaver['about_me_public'])
{
$infos[] = [
'name' => $this->translator->trans('foodsaver.about_me_public'),
'val' => foodsaver['about_me_public'],
];
}
return $infos;
}
/**
* @param array $infos
*
* @return array
*/
>>>>>>> 62feb08c3... make use of "about_me_public" as described on profile page
... change this to what you'd like it to say. Remove the <<< and >>> and === lines.
/**
* @param array $infos
*
* @return array
*/
private function renderAboutMePublicInformation(array $infos): array
{
if ($this->foodsaver['about_me_public'])
{
$infos[] = [
'name' => $this->translator->trans('foodsaver.about_me_public'),
'val' => $this->foodsaver['about_me_public'],
];
}
return $infos;
}
/**
* @param array $infos
*
* @return array
*/
Save.
git add FILENAME
git rebase --continue
Troubleshooting
During development everyone knows the moments when the code shows exactly what you want but the computer just does something different. Some strategies how to find or avoid errors are collected here.
Nightly scripts
With ./scripts/docker-compose run --rm --no-deps app php -f run.php Maintenance daily
you can call the nightly scripts.
Test artifacts
During the Gitlab CI tests are run at every push.
These builds and tests can be found under the menu item CI/CD (the rocket).
There you can already see, which stages (build, test, deploy) passed.
In order to get the detailed test results, go to the job test
in the suitable pipeline (also reacheable via the corresponding MR if existing), click „Browse“ and navigate to tests/_output/_output/report.html
(https://gitlab.com/foodsharing-dev/foodsharing/-/jobs/<job number>/artifacts/browse/tests/_output/_output/report.html
).
CSRF Exception
When working on the API one usually wants to try it out.
If you just type in the API call in the web browser while running the local webpage on localhost:18080
you probably get a CSRF Exception
.
This is a safety feature:
- While you are logined via foodsharing.de other pages can send API calls.
- Since your browser has a session foodsharing.de usually would answer the request, the other page got data that it shouldn't get.
- Solution: foodsharing.de sends a CSRF-token that the browser saves as a cookie and the client reads from the cookie and sends the token as a header with every API call. Since cookies can only be accessed by the correct web page, only the foodsharing.de site can make requests.
- When you just type in the API call the headers including the CSRF-token are not set and you are rejected.
There are several work-arounds:
- You write tests. You should write tests anyway and since they emulate a complete session, the CSRF-Token is sent and valid.
- You add an API call in some javascript-file that gets executed. For example add the following into
/src/Modules/Dashboard/Dashboard.js
:
import { get } from '@/api/base'
get('/activity')
Make sure that you do not commit those temporary changes!
- You disable the CSRF-Check in
/src/EventListener/CsrfListener.php
by commenting the lines
// if (!$this->session->isValidCsrfHeader()) {
// throw new SuspiciousOperationException('CSRF Failed: CSRF token missing or incorrect.');
//}
Make sure that you do not commit those temporary changes!
Restart
Sometimes the docker container get into some weird state. It might help to restart them:
./scripts/stop
sudo ./scripts/clean # sudo necessary since the container run with root privileges and therefore create directories with root ownership
./scripts/start
But it takes quite a while.
Cache
Symfony that is running inside docker container are using a cache directory that is persistent over docker restarts and sometimes changes in the source files are not reflected in the running containers. Then errors that are already fixed might still appear during experiments. Hence sometimes it helps to remove the cache directory:
sudo rm -rf ./cache/dev
or even sudo rm -rf cache
.
Restart, clean and delete cache - Quick and dirty ;-)
./scripts/stop && sudo rm -rf cache && sudo ./scripts/clean && ./scripts/start
This deletes and restarts the docker containers.
Database and email access
The local website gives you database access so that you can directly view and modify what is written in the database. Access to the e-mails that are sent via the website can also be found.
dev | test | |
---|---|---|
Website | localhost:18080 | |
phpadmin (database access) | localhost:18081 | localhost:18080 |
smtp (outgoing email) | localhost:18084 | localhost:28084 |
Those ports are configured in /docker/docker-compose.*.yml
.
Logs
The server (also the local one) writes logs about a lot that happens including errors. To view those logs, run
./scripts/docker-compose logs -f app
where you can also replace app
by other components of the application that are listed by ./scripts/docker-compose ps
or just remove it to show all logs.
docker-compose
also respects the variable FS_ENV
that can be set to dev
or to test
for running either the localhost
(dev) containers or the testing containers.
In order to print specific information in the logs, you can print them in your php
-code.
In order to do so, add a LoggerInterface
in the constructor __construct
:
use Psr/Log/LoggerInterface;
...
private $logger;
...
public function __construct(<other params>, LoggerInterface $logger) {
...
$this->logger = $logger;
}
...
// somewhere in your tested, executed code:
$this->logger->error('some error text');
// especially useful if put into an except clause that catches all errors and reraises them after printing some informative message
Beta Testing
- Allgemeines
- So unterstützt du uns beim Testen
- Und noch ein paar wichtige Punkte
- Noch tiefer einsteigen?
Allgemeines
Alle Neuerungen und Fehlerbehebungen, die auf foodsharing.de online gehen, durchlaufen vorab eine Testphase auf https://beta.foodsharing.de/. Das Beta-Testing dort ist wichtig für uns, da nur so vermieden werden kann, dass wir Fehler auf die Gemeinschaft loslassen und unter Umständen die Seite, die Datenbank oder sogar den ganzen Ablauf beschädigen. Du kannst durch frühes Finden und Melden von Fehlern allen Nutzern (und insbesondere auch den Programmierer*innen) das Leben angenehmer machen. Keiner will nach dem Release einer neuen Live-Version die Nacht durchmachen, wenn auf einmal die Fehler dann erst deutlich werden.
Praktischer Nebeneffekt: Auf der Beta-Seite kannst du nützliche Neuerungen teilweise schon viele Wochen früher nutzen.
So unterstützt du uns beim Testen
-
Die gesamte Kommunikation rund ums Testen findet in der Arbeitsgruppe Beta Testing statt. Du kannst der Gruppe hier beitreten: https://beta.foodsharing.de/?page=groups (Direktlink zur AG, falls bereits beigetreten: https://beta.foodsharing.de/?page=bezirk&bid=734) In der Arbeitsgruppe Beta Testing kommunizieren wir auf Deutsch, an denen meisten anderen Orten auf Englisch.
-
Im besagten Forum melden sich Entwickler*innen mit Testaufträgen (im Normalfall immer dann, wenn gerade eine Änderung an der Seite fertig geworden ist). Dein Job: Die beschriebene Funktion auf https://beta.foodsharing.de/ ausprobieren und Rückmeldung geben: Wenn alles klappt, wie erwartet, reicht ein kurzer Satz oder Daumen hoch als Reaktion auf den Originalbeitrag. Sollte es Probleme geben, beschreibe bitte so ausführlich wie möglich was du getan hast und was nicht funktioniert hat. Wichtig: Gib nach Möglichkeit zu allen Testaufträgen Rückmeldung, auch wenn das manchmal ein bisschen Arbeit bedeutet – nur so bekommen wir ein vollständiges Bild und finden alle Probleme.
-
Du kannst https://beta.foodsharing.de/ ausschließlich für Testaufträge oder auch dauerhaft nutzen. Beide Versionen der Seite greifen auf die gleichen Daten zu und bieten (bis auf neue Features und Fehlerbehebungen) die gleichen Funktionen. Aber: Obwohl wir grundsätzlich versuchen, nichts kaputt zu machen, können sich Fehler einschleichen. In einigen Fällen (und gerade dann, wenn etwas nicht wie gewollt funktioniert) ist es daher sinnvoll, auf foodsharing.de auszuweichen.
Und noch ein paar wichtige Punkte
-
Das Forum kannst du auch nutzen, um auf Probleme aufmerksam zu machen, für die es keinen Testauftrag gibt oder die du keinem Auftrag zuordnen kannst. Wichtigstes Kriterium für eine Fehlermeldung: Auf beta.foodsharing.de ist es kaputt und auf foodsharing.de nicht.
-
Unter jedem Testauftrag findet sich ein Link zu gitlab.com, dem Portal, auf dem die Entwicklung koordiniert wird. Hier finden sich oft noch mehr Informationen zur jeweiligen Änderung.
Noch tiefer einsteigen?
Auch über das Bearbeiten von Testaufgaben hinaus kannst du uns unterstützen, zum Beispiel durch das Anlegen und Betreuen von Fehlerberichten, sogenannten Issues. Mit einem kostenlosen Account bei GitLab kannst du solche Issues für das Foodsharing-Projekt unter https://gitlab.com/foodsharing-dev/foodsharing/issues anlegen. Es gibt verschiedene Templates, mit denen diese Meldungen strukturiert werden können (und sollten). Wichtig: Die Issues sind idealerweise so ausführlich, dass auch Menschen sie nachvollziehen können, die (noch) keine aktiven Foodsaver sind. Hilfreich sind Screenshots und Schritt-für-Schritt-Anleitungen, mit denen sich Fehler reproduzieren lassen.
Zu guter Letzt: Herzlichen Dank, dass du mitmachst! Sowohl die IT als auch alle Nutzer*innen der Seite sind dir sehr dankbar (auch wenn Letztere manchmal nicht wissen, wieso).
PHP
This page describes broadly how PHP is used in our project:
- Main entry point
- Autoloading
- Service classes
- Automatic service injection
- Syntax
- Conventions / Coding Style
For more specific explanations of the types of classes we use, make sure to check PHP Structure!
Main entry point
The main entry point for the web is /index.php
.
That means that /index.php
gets called whenever a https://foodsharing.de
-request gets sent to the website.
Another entry point is xhr.php
, which is used for routes starting with https://foodsharing.de/xhr.php
. These are
used for our legacy API (see Xhr). The same applies for xhrapp.php
.
These three entry points are now just standard Symfony entry points.
The relevant (custom) code has been moved to src/Entrypoint
, where three respective controllers do the actual work.
For the IndexController
, a large part of the code has been moved to src/EventSubscriber/RenderControllerSetupSubscriber.php
.
The fourth entry point is restApi.php
, which will be used whenever a URL starting with https://foodsharing.de/api
is
requested. This is the route to our modern API following REST principles (see REST-API).
It is also a standard Symfony entry point.
Dependencies and Dependency Injection
Autoloading
(Almost) no code comes without dependencies on other PHP classes.
In order to use a class defined in another file, it needs to get imported at the beginning of your file
using use
, following a namespace.
The namespace, starting with Foodsharing
gets interpreted by the composer autoloader.
This is configured in /composer.json
under the key "autoload"
, where Foodsharing
gets mapped to /src
.
Other namespaces than Foodsharing
link to external libraries, which have their source code somewhere inside
the /vendor
directory.
The composer autoloader loads files corresponding to conventions specified by the PSR-4 standard.
That means that every subnamespace following the Foodsharing
namespace gets interpreted as subdirectory under
/src
.
use
is not necessary for using classes in the same namespace (roughly: same directory).
Loading a depencency via require
is just used in files
like index.php
, which are not in the /src
directory and therefore can't use autoloading.
require
basically executes the PHP file unter the given file name, so you can use the class declaration defined in
that file. Don't use require
if you can use autoloading.
Services
A service class is a class whose main purpose is not representing an object structure, but providing functionality. Service classes are used to structure operations using object oriented design patterns.
What exactly a service is and what not, is not well defined (see Blog Post Services in Domain-Driven Design), but there are some characteristics that are typical for services
- only one instance is created per requests and then shared by all classes
- services depend on other services and the non-service objects (like DTOs) they operate on
- non-service objects don't depend on services
As we don't have any entity classes, except for the DTO classes, nearly all of our classes are services.
Because service classes only need to be instantiated once, we don't use
the new
statement to create instances. Instead, we use the
Dependency Injection pattern.
This enables us to share service instances throughout the application.
Automatic service injection
Responsible for creating and injecting the instances is the Symfony Dependency Injection component.
If we want Symfony to inject a dependency into our service, all we need to do is mentioning
the class in our constructor (__construct
), e.g.
class ActivityXhr extends Control {
private $mailboxGateway; /* attributes (member variables) */
public function __construct(ActivityModel $model, MailboxGateway $mailboxGateway)
{ /* using arguments for setting attributes */ }
... }
Dependency injection (Symfony) then makes sure that every service we request is created and injected when our service is instanciated.
This works because we only need at most one object of every service class. This is because, as already mentioned, service classes are not about representing objects using instances, but about the functionality they provide.
Symfony config is in /config/services.yml
. This configuration makes sure that services
get created automatically. See the Symfony docs
for further reference.
Syntax
Here we collect the parts of the PHP language that we use in this project. As I write this I already got some experiences in other languages and therefore only include short explanations of surprising syntax.
- Variables: all occurences of variables are starting with a Dollar (
$
) symbol:
$out = '<ul class="linklist baskets">';
=
is an assignment'string'
and"string"
are strings. Variables inside double-quoted string literals get replaced by their values..
is the concatenation operator for strings (in other languages+
).=
adds the string to the right to the variable on the left$var->member
refers to a member variable or method of an object (in other languages.
)ClassName::member
refers to a (static) member variable or function of a class...
is used for packing and unpacking arrays in argument lists (packing in function definition argument list, unpacking in function use argument list). Longer explanation on stackoverflow
Conventions
- Do not use global variables (those indicated by the keyword
global
, can be found in legacy code) - Indentation: we use one tabstop per indentation level
- Variables in strings: we do not use variables in strings but concatenate:
$list = 'bla'
$list .= $list . 'some text' . $someVariable . 'end text'
- When (re)writing php code add types in arguments and return types of functions. If you work with existing code it is not always trivial and is therefore not enforced. In general:
- as a parameter, something should be either the type (e.g.
string
,int
) ORnull
if okay to not be set.?string $blub = null
works as a parameter definition to allow that. - as a return type, something should always ever be one type, if possible. Throw an exception otherwise. Especially an empty array
[]
is fine to say that there is no data when otherwise data would have been returned as an array.
- as a parameter, something should be either the type (e.g.
Code structure
For the structure of the PHP code, see the following sections. Different kinds of classes and concepts are explained there:
If you are looking for a general description of our PHP setup, please check PHP!
Modules
A lot of code is sorted into modules in the /src/Modules
directory.
This is a sorting by topic: each module contains files for one topic.
That can be a gateway,
a controller, an (old) view, javascript, css, (old) XHR,
(old) models.
The Rest api controllers do not go into
their respective module directory but into the /src/RestApi
directory. This does not have a good reason but it's the way it is now.
Deprecated module structure
Since legacy code is still widespread through the repository it is important to understand it, too.
The (php) code is roughly structured with Model - View - Controller.
The communication with the database is found in Model classes.
For example we can find sql
-commands to manipulate a foodsaver in /src/Modules/Foodsaver/FoodsaverModel.php
.
Those are executed with the functions inherited from the Db
class (see use Foodsharing\Lib\Db\Db;
, for example $this->q(...)
where q
stands for query
.
Newer module structure
Instead of Model classes, that hold both, data query logic and domain logic, we move towards splitting these up into Gateway classes and Transaction classes.
For a general description what „domain logic“ is, see section Transactions.
Note that all of the following guidelines have a lot of exceptions in the existing code. Nevertheless try to heed the following guidelines in code you write and refactor.
Gateways
Our concept of Gateway classes follows the Table Data Gateway pattern.
One main difference to Models is that a Gateway doesn't contain the actual model of an entity, as the overall domain logic is put into Transactions while the structure lives in Data Transfer Objects.
The purpose of a Gateway is to provide functionality to query instances of a certain entity type from the database. If you are familiar with ORM based architectures, you might compare the Gateway's responsibility to the one of a Repository.
As methods to be found on a Gateway class have the job to perform queries, they should be named in a way that
portrays this. They should not pretend to perform domain-related business logic. A method name suitable for a
Gateway class would be selectResponsibleFoodsavers()
or insertFetcher()
. A method not suitable would be
addFetcher()
, as this implies that the method took care of the whole transaction of adding a fetcher to a store
pickup.
In particular permission checks are not to be found in Gateways.
Another difference to models regarding the implementation of SQL queries is that the functions to communicate with the
database are not directly in the Gateway class by inheritance but encapsulated in the attribute
db
($this->db-><functioncall>
) of class Database
defined in /src/Modules/Core/Database.php
.
Gateways inherit from BaseGateway
(/src/Modules/Core/BaseGateway.php
), which provides them with the $db
attribute.
If possible, use semantic methods like $db->fetch()
or $db->insert()
to build your queries.
Often, requesting information from the database uses sql
calls via the functions at the end of the Database class, like
$db->execute()
- don't use these unless you can't build your query otherwise.
All of those functions are well-documented in /src/Modules/Core/Database.php
.
Individual gateway functionality
Please refer to our list of Gateway classes below if you're looking for specific functionality:
ActivityGateway.php
ApplicationGateway.php
- handles workgroup applications
BasketGateway.php
- adding, editing, requesting food baskets, managing their availability
- querying food basket data, listing new baskets nearby
BellGateway.php
BlogGateway.php
BuddyGateway.php
- add someone as buddy, respond to that, get list of buddies
BusinessCardGateway.php
ContentGateway.php
- basic CMS functionality: display, create, edit, delete pages with fixed contentId
- some content is used in page templates and just a sentence, other content consists of full pages
DashboardGateway.php
- just basic user info
- we have an issue to investigate if `countStoresWithoutDistrict` & `setbezirkids` are still needed
EmailGateway.php
EventGateway.php
- add or edit events, manage invitations (target audience) and their RSVP
- get list of events in a region, query people who are interested
- also has some weird event location storage
FoodsaverGateway.php
- almost 1000 lines of code :)
FoodSharePointGateway.php
GroupGateway.php
- groups handle functionality that is shared between both regions and workgroups
- currently only has a few basic helper, and the complex hull closure computation
GroupFunctionGateway.php
- group functions are currently only used for workgroups, but can attach to both regions and workgroups
- includes adding and removing the special function groups, and querying whether they exist
- there are 3 available functions right now; see `Modules/Core/DBConstants/Region/WorkgroupFunction.php`
LegalGateway.php
LoginGateway.php
LookupGateway.php
MailboxGateway.php
MailsGateway.php
MaintenanceGateway.php
- data needed for cleanup and bookkeeping executed each night (see `MaintenanceControl.php`)
MapGateway.php
MessageGateway.php
MigrateGateway.php
PassportGeneratorGateway.php
ProfileGateway.php
PushNotificationGateway.php
QuizGateway.php
QuizSessionGateway.php
ForumGateway.php
ForumFollowerGateway.php
RegionGateway.php
WorkGroupGateway.php
ReportGateway.php
- currently unused
SearchGateway.php
SettingsGateway.php
StatisticsGateway.php
StatsGateway.php
StoreGateway.php
TeamGateway.php
UploadsGateway.php
VotingGateway.php
WallPostGateway.php
Transactions
All modules have certain business rules/domain logic to follow when their data is modified. After all, there are always certain operations that have to be executed together to ensure that the data keeps being consistent according to the the rules that apply to them in reality. We implement these transactions of operations executed together as methods on Transaction classes.
For example, when someone wants to join a store pickup, it's not enough to just insert this information into the database. We also have to be check if the user has the rights to join without a confirmation, and if not, we have to make sure that the store owner gets notified that they should confirm or deny it.
This is why joining a pickup is implemented in the joinPickup()
method on the corresponding Transaction class. All
controllers should use this transaction if they want to make a user join a pickup, because only if all steps of the
transaction are executed, the pickup joining is complete.
What should not be part of a transaction class:
- knowledge of the underlying database (should still work with a gateway reading from punched cards)
- knowledge of request types (e.g. should be callable from a desktop application or some different internet protocol). Therefore transaction classes do not raise HTTPException or choose HTTP response codes or the json representation of responses
- the session - but at this point we are not strict, so far transaction classes use information of the session
Permissions
Permission classes are used to organize what actions are allowed for which user. They are a special type of transaction class.
Data Transfer Objects
Currently, domain objects are often represented differently: Some methods receive and return them as associative arrays, some receive them as a very long list of parameters. If arrays are used, it's often unclear which format the output has and which format the input is expected to have. Parameter lists on the other hand can get very long, and if parameters are documented, the documentation for one domain object is spread around the code.
For further structuring Data Transfer Objects (DTO) can be used. An example can be found in the Bell module, introduced in the merge request !1457.
DTOs help with clearing up which parameters are expected when and what types they have. DTO classes have public properties and don't encapsulate logic or functionality. Only logic to create DTOs or convert them from other representations shall be implemented on the DTO classes as static methods.
As objects are often represented differently, as only parts of them are needed, most domain objects have multiple DTO
representations. That's why we put them in a DTO
directory inside of the corresponding module directory. Usually,
there is one main or "complete" representation, that includes all aspects of the domain object that can be found in its
database table. This one is just named like the domain object itself (e. g. Bell
). All other partial represantations
can be named according to their purpose or the place they are used (e. g. BellForList
).
Controllers
Controllers handle requests.
They define how to extract relevant information from the
request, check permissions by calling the correct Permission
and calling the suitable transaction.
They define which HTTP response including the response code
is sent back and the conversion of internal data to json
(return $this->handleView(...)
).
Since the business logic („What is part of an event (= transaction)?“) is in the transaction classes, a controller method usually just calls one actual transaction method (apart from permission checks). It can read necessary information from the session to give those as arguments to the transaction class.
We have:
- REST controllers with the name
<submodule>RestController.php
- (legacy) XHR controllers with the name
<module>Xhr.php
- (legacy) render controllers with the name
<module>Control.php
- modern render controllers with the name
<module>Controller.php
Render controllers are called that because they always render a part of the website, as opposed to API controllers (like REST and XHR), which are usually called by the rendered website (client) and return data, not an HTML document.
For a guide to refactoring legacy HTML controllers to modern controllers, see the PHP controller refactoring guide
Services
Currently, in our source code, some code that assists controllers can be found
in classes named "Service": /src/Services
.
Some of these classes are Transaction classes that need to be renamed, and some
of them are utility classes. /src/Services/SanitizerService.php
is the best
example for that.
Some code in the services should rather go into the modules if they belong to a specific module.
Also see the section Services for a broader use of this term.
Helpers
The content of /src/Helpers
is a collection of code that
somehow had no better place. The word Helper
does not say anything.
Rather try to find a suitable place for it.
Routing
For the new REST API, Routing happens completely through Symfony, using @Route
annotations in the respective controllers.
(also, see config/routes/api.yaml
)
Everything else (the website, xhr and xhrapp) uses GET parameters to determine the controller and action to call.
See src/Entrypoint
for the implementations,
and src/Lib/Routing.php
for how the page=
GET parameter corresponds with controller class names.
Last, there are some special routes that consist of:
- a
location
and atry_files
directive in the web server's config For the development environment, you can find them here: https://gitlab.com/foodsharing-dev/images/-/blob/master/web/foodsharing.conf - Symfony routes to make symfony call the correct entrypoint for all possible URI forms in
config/routes/special.yaml
.
Deprecated module structure
Since legacy code is still widespread through the repository it is important to understand it, too.
The (php) code is roughly structured with Model - View - Controller.
The communication with the database is found in Model classes.
For example we can find sql
-commands to manipulate a foodsaver in /src/Modules/Foodsaver/FoodsaverModel.php
.
Those are executed with the functions inherited from the Db
class (see use Foodsharing\Lib\Db\Db;
, for example $this->q(...)
where q
stands for query
.
Newer module structure
Instead of Model classes, that hold both, data query logic and domain logic, we move towards splitting these up into Gateway classes and Transaction classes.
For a general description what „domain logic“ is, see section Transactions.
Note that all of the following guidelines have a lot of exceptions in the existing code. Nevertheless try to heed the following guidelines in code you write and refactor.
Libraries
Please explain the general content of /src/Lib
after understanding it.
Refactoring
We want to continue refactoring the codebase. This will lead to code which is more modular, easier to maintain and clearer. A lot is explained in the book "Modernizing Legacy Applications In PHP" (mentioned here in more detail)
There is an overview issue with a checklist.
If you have an idea for a new refactoring concept, please think, before implementing, if this would increase the work for others :).
Front-end
Currently, we use three different ways for the front-end code.
The oldest one is in the View files, in which php functions build the HTML and JavaScript code of the website.
If you refactor something or want to make something new, please use vue.js
There are also twig templates used.
It is not necessary to refactor these solely for the purpose of refactoring, but if you try to fix something in an old file, it would be great to refactor it to vue.js then. If you are making a new front-end page, you should definitivly use vue.js.
Network
Request handling is explained in the here and more about Rest API endpoints can be found here.
Back-End
Some explanation can be found here.
Helper classes could be used to put some functions unorganized there. Please think about if there might not be a better class to put it. Some parts might be better in Service classes. (If in doubt, please ask the team.)
Database Access
Currently there are SQL statements in *Model
classes, in XhrMethods and in *Gateway
classes.
More information can be found here.
Issue #9 tracks the refactor procress of moving everything to *Gateway
classes.
Internationalization
We want the code to be free from German-specific texts to enable non-German speakers to use the site and to make it easier for groups in other countries to use the code. Unfortunately, we are not quite there yet, but a lot of progress has been made and the remaining hardcoded strings are indicative of obvious legacy code.
We use the Symfony TranslatorInterface
to replace translation keys (given in code) with their translated values. Translations are read from files in YAML format: for German that would be /translations/messages.de.yml
.
Aside from those German strings, there are four mail ways in which fixed text on the website can be given in the source code with our translation mechanisms:
- In PHP frontend/view code
Classes derived from Control and View already contain the TranslatorInterface, which is accessible as
$this->translator
, and itstrans()
function that resolves translation keys.
Other helpers are including it like this:
use Symfony\Contracts\Translation\TranslatorInterface;
// instantiate or inject (usually autowired)
$this->translator->trans('fsp.acceptName', ['{name}' => $foodSharePoint['name']])
- From JavaScript code
In
client/src/i18n.js
we build a basic replacement function that imports translation resources, replaces variables if needed, and returns the translated value if one exists. Fallbacks are implemented for English and German, which are currently the only languages for which we bundle translations.
To use this function elsewhere, import the module like so:
import i18n from '@/i18n'
pulseInfo(i18n('basket.not_active'))
- As part of Vue templates
In
client/src/vue.js
we define the$i18n
prototype and attach it to all Vue templates. This is the preferred way of frontend translation. If you're translating component parameters, make sure to :bind them accordingly::title="$i18n('button.clear_filter')"
- As part of Twig templates (Legacy)
The
trans
filter allows passing translation keys to the translation engine from Twig files. Examples:
{% raw %}{% embed 'components/field.twig' with {'title': 'events.bread'|trans} %}{% endraw %}
{% raw %}<h4>{{ 'dashboard.push.title'|trans }}</h4>{% endraw %}
Do not create more of these unless you really know what you're doing! You will need to be very careful with the syntax for replacing variables ({% raw %}|trans({'%name%': name}{% endraw %})
).
Helper scripts
There are a number of helper scripts available. Most of them obey the FS_INT
env var. Default is dev
, you can also set it to test
.
Script overview
Script | Purpose |
---|---|
./scripts/ci.test | |
./scripts/clean | Remove anything added by start /test commands |
./scripts/codecept | |
./scripts/composer | Run php composer |
./scripts/deploy.notifyslack.sh | |
./scripts/deploy.sh | |
./scripts/dev | Run webpack dev server for doing js dev (obsolete, included in ./scripts/start ) |
./scripts/docker-compose | Docker-compose with the correct options set for the environment |
./scripts/dropdb | Drop the database |
./scripts/fix | runs all fixing - code stuff (php) |
./scripts/fix-codestyle-local | fix php code style, see php Code style |
./scripts/generate-revision.sh | |
./scripts/inc.sh | defines functions needed in other scripts |
./scripts/initdb | Create the database and run migrations |
./scripts/lint | runs all lintings scripts lint-... |
./scripts/lint-js | lints javascript and vue files: prints errors etc. |
./scripts/lint-markdown [files|directories|globs] | lints markdown files: prints errors etc. NOTE: Custom args must originate from client/ directory (e.g. ../README.md for root file) |
./scripts/lint-php | lints php files: prints errors etc. |
./scripts/mkdirs | Create directories that need to be present (called by other scripts) |
./scripts/mysql | Run mysql command in correct context: ./scripts/mysql foodsharing "select * from fs_foodsaver" |
./scripts/mysqldump | Run mysqldump command in correct context |
./scripts/php-cs-fixer | |
./scripts/php-cs-fixer.ci.sh | |
./scripts/rebuild-all | |
./scripts/rebuild-container | |
./scripts/rebuild-test-data | |
./scripts/rm | Shut down and clean up all containers |
./scripts/run | |
./scripts/seed | Run seed scripts in scripts/seeds/*.sql |
./scripts/start | Start everything, initializing anything if needed, see Setting things up |
./scripts/stop | Stop everything, but leave it configured see Setting things up |
./scripts/test | Run tests |
./scripts/test-chat | Run test for the chat |
./scripts/test-js | Run test for the client (JS) |
./scripts/test-rerun | Run tests without recreating db (faster that test) |
./scripts/watch-assets | Builds the static assets on change |
Nightly maintenance
Using the docker-compose
you can run various php-scripts, e.g.
./scripts/docker-compose run --rm --no-deps app php -f run.php Stats foodsaver
./scripts/docker-compose run --rm --no-deps app php -f run.php Stats betriebe
./scripts/docker-compose run --rm --no-deps app php -f run.php Stats bezirke
This runs the statistics scripts that are run nightly on the production server.
This can be necessary to test code concerning statistics since they are usually never run locally.
--rm
removes the containers afterwards, --no-deps
lets docker not worry about any dependendent containers. This is often useful since they are often running already.
HTTP Request
The traditional loading of a page is a http
request,
e.g. calling the main address https://foodsharing.de
calls /src/Entrypoint/IndexController.php
which uses other php
files to answer the request.
The php
builds html
, css
and javascript
and sends them to the client.
Other ways to interact with the foodsharing platform are:
- (Legacy) XHR - do not use in new code!
- the REST API endpoints - the preferred option
- our chatserver
XHR
XHR (XMLHttpRequest) is used throughout the project for historic reasons, but should be replaced with modern API endpoints where possible. So do not implement new features with XHR! The following is just documentation to understand what exists :)
We used XHR for information transferred from the server to the client which is not a complete new page but javascript-initiated.
For example, the Update-Übersicht on the Dashboard was loaded by an XHR that gets a json file with the information of the updates.
The javascript was found in /client/src/activity.js
, and
it called XHR endpoints like http://foodsharing.de/xhrapp.php?app=basket&m=infobar
.
This requests an answer by /src/Entrypoint/XhrAppController.php
which in turn calls the correct php
file based on the options that are given after the ?
in the url.
For example, the activity.js
requests were answered by
/src/Modules/Activity/ActivityXhr.php
.
In this example, the database was queried for information via ActivityModel.php
which in turn used the /src/Modules/Activity/ActivityGateway.php
.
There are a two mostly identical XHR endpoints - /xhr.php
and /xhrapp.php
. Nowadays, those are handled by XhrController.php
and XhrAppController.php
respectively.
XHR-request answers contain a status and data and ? and always sends the HTTP status 200. So errors are not recognizable by the HTTP status, but by a custom status in the returned json response.
REST API
The more modern way to build our api is a REST api by FOS (friends of symfony). The documentation of the REST api endpoints is located at the definition of the endpoints and can be nicely viewed on (https://beta.foodsharing.de/api/doc/).
In the documentation you can read how to properly include the documentation.
A good example can be found in /src/RestApi/ForumRestController.php
.
In the Code quality page we have some notes on how to define the REST API Endpoints.
The javascript code that sends REST API requests is found under /client/src/api
and is used by other javascript by import.
All php classes working with REST requests are found in /src/Modules/RestApi/<..>RestController.php
.
This is configured in /config/routes/api.yml
.
There it is also configured, that calls to /api/
are interpreted by the REST api, e.g.
https://foodsharing.de/api/conversations/<conversationid>
This is being called when you click on a conversation on the „Alle Nachrichten“ page.
REST is configured via annotations in comments in functions.
@Rest\Get("subsite")
specifies the address to access to start this Action: `https://foodsharing.de/api/subsite"@Rest\QueryParam(name="optionname")
specifies which options can be used. These are found behind the?
in the url:http://foodsharing.de/api/conversations/687484?messagesLimit=1
only sends one message.- Both
Get
andQueryParam
can enforce limitations on the sent data withrequirement="<some regular expression>"
. @SWG\Parameter
,@SWG\Response
, ... create the documentation (see above)
Functions need to have special names for symfony to use them: the end with Action
.
They start with a permission check, throw a HttpException(401)
if the action is not permitted.
Then they somehow react to the request, usually with a Database query via the appropriate Model or Gateway classes.
During running php, the comments get translated to convoluted php code. REST also takes care of the translation from php data structures to json. This json contains data. Errors use the error codes of http-requests.
While reading and writing code a (basic) manual and an annotation overview will help.
nodejs for messages
The chats have a separate way of communication between client and server.
For all other pages the initiative starts at the client,
the client sends a request to the (php
) server and gets an answer.
Each request uses one connection that is closed afterwards.
This is not useful for the chats since the server knows that there are new messages and has to tell the client.
For this case there exists a separate nodejs
server (on the same machine as the php
server but separate). This holds an open connection to each user that has foodsharing.de
open on their device. Each time a message arrives at the php server, it sends this information to the nodejs
server via a websocket
which uses the connection to the client to send the message.
Note that there can be several connections to each session, of which there can be several for each user. nodejs
sends the message to all connections of all addressed users.
The code for the nodejs
server is found in /chat/src/index.ts
and other files in /chat/src
chat/socket.io -> nodejs server, in chat/src/index.ts. There is documentation for all used parts in /chat/node_modules/<modulename>/Readme.md
. All nodejs
-documentation is found on their webpage.
XHR
XHR (XMLHttpRequest) is used throughout the project for historic reasons, but should be replaced with modern API endpoints where possible. So do not implement new features with XHR! The following is just documentation to understand what exists :)
We used XHR for information transferred from the server to the client which is not a complete new page but javascript-initiated.
For example, the Update-Übersicht on the Dashboard was loaded by an XHR that gets a json file with the information of the updates.
The javascript was found in /client/src/activity.js
, and
it called XHR endpoints like http://foodsharing.de/xhrapp.php?app=basket&m=infobar
.
This requests an answer by /src/Entrypoint/XhrAppController.php
which in turn calls the correct php
file based on the options that are given after the ?
in the url.
For example, the activity.js
requests were answered by
/src/Modules/Activity/ActivityXhr.php
.
In this example, the database was queried for information via ActivityModel.php
which in turn used the /src/Modules/Activity/ActivityGateway.php
.
There are a two mostly identical XHR endpoints - /xhr.php
and /xhrapp.php
. Nowadays, those are handled by XhrController.php
and XhrAppController.php
respectively.
XHR-request answers contain a status and data and ? and always sends the HTTP status 200. So errors are not recognizable by the HTTP status, but by a custom status in the returned json response.
REST API
The more modern way to build our api is a REST api by FOS (friends of symfony). The documentation of the REST api endpoints is located at the definition of the endpoints and can be nicely viewed on (https://beta.foodsharing.de/api/doc/).
In the documentation you can read how to properly include the documentation.
A good example can be found in /src/RestApi/ForumRestController.php
.
In the Code quality page we have some notes on how to define the REST API Endpoints.
The javascript code that sends REST API requests is found under /client/src/api
and is used by other javascript by import.
All php classes working with REST requests are found in /src/Modules/RestApi/<..>RestController.php
.
This is configured in /config/routes/api.yml
.
There it is also configured, that calls to /api/
are interpreted by the REST api, e.g.
https://foodsharing.de/api/conversations/<conversationid>
This is being called when you click on a conversation on the „Alle Nachrichten“ page.
REST is configured via annotations in comments in functions.
@Rest\Get("subsite")
specifies the address to access to start this Action: `https://foodsharing.de/api/subsite"@Rest\QueryParam(name="optionname")
specifies which options can be used. These are found behind the?
in the url:http://foodsharing.de/api/conversations/687484?messagesLimit=1
only sends one message.- Both
Get
andQueryParam
can enforce limitations on the sent data withrequirement="<some regular expression>"
. @SWG\Parameter
,@SWG\Response
, ... create the documentation (see above)
Functions need to have special names for symfony to use them: the end with Action
.
They start with a permission check, throw a HttpException(401)
if the action is not permitted.
Then they somehow react to the request, usually with a Database query via the appropriate Model or Gateway classes.
During running php, the comments get translated to convoluted php code. REST also takes care of the translation from php data structures to json. This json contains data. Errors use the error codes of http-requests.
While reading and writing code a (basic) manual and an annotation overview will help.
nodejs for messages
The chats have a separate way of communication between client and server.
For all other pages the initiative starts at the client,
the client sends a request to the (php
) server and gets an answer.
Each request uses one connection that is closed afterwards.
This is not useful for the chats since the server knows that there are new messages and has to tell the client.
For this case there exists a separate nodejs
server (on the same machine as the php
server but separate). This holds an open connection to each user that has foodsharing.de
open on their device. Each time a message arrives at the php server, it sends this information to the nodejs
server via a websocket
which uses the connection to the client to send the message.
Note that there can be several connections to each session, of which there can be several for each user. nodejs
sends the message to all connections of all addressed users.
The code for the nodejs
server is found in /chat/src/index.ts
and other files in /chat/src
chat/socket.io -> nodejs server, in chat/src/index.ts. There is documentation for all used parts in /chat/node_modules/<modulename>/Readme.md
. All nodejs
-documentation is found on their webpage.
javascript
Javascript is code that is run in the browser of the client.
For every page (module), the main javascript file is found under /src/Modules/<modulename>/...js
. This is automatically sent to the client.
All other javascript (should) be found under /client
.
imports
Javascript has different ways of using (importing) code from other files.
We use npm
, the standard package manager for javascript.
All used third-party-packages are listed under /client/package.json
.
For using a package, we use the import
command at beginnings of files.
During build of the webpage the imports are resolved (see webpack) and only what is necessary is sent to the user.
To enable small bits of javacode somewhere (inline), there is /client/src/globals.js
.
There a bunch of functions are made avaiable globally.
This is imported in the main module js-files via import '@/core'
and import '@/globals'
.
webpack
The javascript files are not directly sent to the client but preprocessed by webpack.
Webpack is configured via /client/webpack.base.js
.
For example this includes the alias that translate @
in imports into /client/src
.
vue.js
The modern way of designing front end pages is vue.js
.
We try to use more of it do get more order into javascript files.
The big advantage is, that html, javascript and css are clearly separated.
One example is /client/src/components/Topbar/Login.vue
.
Before diving into happy vue.js
-hacking you probably should read a bit in the vue documentation.
Icons
For including icons in the website we do not create a lot of them ourself but use Font Awesome. In order to use an icon, use the code proposed by Font Awesome. For example it looks like
<i class="fas fa-user" />
in html code like .vue-js files.
That explains where this unexplained class="fas/r/b
code comes from.
MySQL database
The MySQL database saves data on a hard drive.
It holds all long-term information.
Querying information is done via sql
in Model.php
and Gateway.php
classes.
More detailed information about queries can be found in the php reference.
Related issue: Extract SQL Statements To Gateways.
Database tables and columns
As described in Set up and Database access we can view the dev database in a browser via phpmyadmin. Many table and column names should be self-explanatory. Many are not unfortunately. (If you create new tables, make sure a comment is not necessary!) That's why here we start a list with explanations to the tables and columns. Please add to this when it was not obvious to you what a table/column was representing and you figured it out. If you found this information well described in some file (e.g. some Gateway-php-file), please just link this location to avoid information duplication.
Some information can also be inferred by the list of limitations and problems
listed in /database_fixup.md
in the top level directory.
Theoretically there is also the possibility to add a comment for the column in the database, e.g. for team status in fs_betrieb. It hasn't been established to use those and adding them later is not as easy as adding the information here since it would require Database migration.
The tables also specify indices. That are columns that are often searched. Read the php manual for more detailed explanation.
Redis database
The Redis database saves data in memory. It holds all short-term information and caches some of the information gotten from the MySQL database. Information in Redis include session IDs (Who is loged in?), and email queues.
Database Migration
We are using phinx for database migrations. If your code change requires customization of the database,
migration templates can be created with ./scripts/docker-compose exec app vendor/bin/phinx create MyNewMigration
Workaround (Here we should look for a better solution)
Run the command
sudo chmod 775 migrations/yourfile
before your first edit.
You can test the migration with ./scripts/docker-compose exec app vendor/bin/phinx migrate --dry-run
(which "runs" all not yet applied migrations which in that case should be just your new one).
For examples you can have a look at migrations/ folder and https://book.cakephp.org/phinx/0/en/migrations.html.
Database tables and columns
Since tables are sorted alphabetically in phpmyadmin, sort them here alphabetically:
fs_abholer
- decribes who fetches when where and if confirmed
- confirmed
1
, not yet confirmed0
fs_abholzeiten
Contains information about regurlary reoccuring pickup slots. Additional single pickup slots are stored in #TODO: find table. The columns to be described are
column | description | possible values |
---|---|---|
dow | day of week | 1 = Monday, 0 = Sunday |
time | when on the day the pickup is | time |
fetcher | number of slots | >= 0, >= 1 enforced by frontend |
fs_bezirk
describes the regions
- type: description in
src\Modules\Core\DBConstants\Region\Type
fs_foodsaver
deleted_at
: deletion day of account, ifNULL
, account is active
fs_foodsaver_has_bezirk
describes which foodsaver is in which workgroups and regions
anything with theme
theme
are threads in the forum.
Tests
We use Codeception for testing, especially testing the php code.
Useful commands and common pitfalls
Useful commands for testing and common pitfalls.
Command | Action | Pitfall |
---|---|---|
amOnPage | Changes URL, loads page, waits for body visible | Do not use to assert being on a URL |
amOnSubdomain | Changes internal URL state | Does not load a page |
amOnUrl | Changes internal URL state | Does not load a page |
click | Fires JavaScript click event | Does not wait for anything to happen afterwards |
seeCurrentUrlEquals | Checks on which URL the browser is (e.g. after a redirect) | |
submitForm | Fills form details and submits it via click on the submit button | Does not wait for anything to happen afterwards |
waitForElement | Waits until a specific element is available in the DOM | |
waitForPageBody | Waits until the page body is visible (e.g. after click is expected to load a new page) |
Releasing
We want to release the beta version of the foodsharing website to production every two months. For one to two weeks, we stop merging features and focus on testing and bug fixing. If there are features not to be used for the next release, they are disabled. If there are still release blockers, we will talk about them in a call and decide what to do.
As soon as everything is ready, the master branch can be merged into the production branch. People with rights for this can be found in the gitlab-Wiki.
For organization, we use gitlab milestones. Their titles consist of the month and the year of the release and a fruit. If you are working on something which belongs to the next release, feel free to add it to the milestone. Please don't recycle milestones, but always use a new one for each release.
Workflow
Since we can tag the latest commit of the release on branch master, it is not necessary to create a new branch for the release. Also, in contrast to hotfixes which are cherry-picked, it is not necessary to merge the changes back into master after the release.
- Update the date of the release in the changelog and commit it to branch master.
- Add a new tag on the latest commit in master. We use the date in the format
2021-09-24
for the tag name.- either on the command line using
git tag 2021-09-24
andgit push –tags
- or in the project's tag list on GitLab
- either on the command line using
- Create a new merge request in GitLab from
master
toproduction
. Merge it and wait for the deployment to finish. - Add a new section to the changelog and commit it to master.
Hotfix deployment
Preparation and merge:
- Start on production branch and create new branch from it (e.g. branch
hotfix-20200615
) - Cherry pick commits from master branch (
git cherry-pick {commitId}
) - picking commits from MRs / branches that have not been merged into master creates differences between master and production that will be annoying in the next release
- optionally check git log history and diff (e.g.
git diff origin/production
) - add new hotfix section to changelog
- there might be other merge conflicts in the changelog -> fix them manually (maybe change auto merge for the changelog in the future?) and commit
- the hotfix branch can be pushed to run the pipeline and to check if the tests are ok
to merge:
- either switch back to production branch and merge hotfix branch into it
- or create an MR in gitlab, target it towards production (defaults to master) and click merge (needs another approver)
Check
- Do we need database changes?
- Do we need to restart any services that are not automatically restarted?
- Note that: all services run in docker container in dev environment but on bare machine on production
Afterwards
- merge your changes back into the master branch:
git checkout master; git merge production
(don't forget to update your local branch before) - possibly, you get conflicts here to be solved. It is important to do that now and not at the next release, so the person doing the next release is not annoyed :-)
- make the changelog nice again and commit it into the merge commit:
git commit --amend
Update our software dependencies
Slack
Every Sunday a schedules pipeline "send outdated dependency report to slack" is started and the result can be read in the channel #fs-outdated.
Update from backend using Composer
Manually check the version
./scripts/composer outdated -D
Restricts the list of packages to your direct dependencies
The color coding is as such:
green (=): Dependency is in the latest version and is up to date.
yellow (~): Dependency has a new version available that includes backwards compatibility breaks according to semver, so upgrade when you can but it may involve work.
red (!): Dependency has a new version that is semver-compatible and you should upgrade it.
https://getcomposer.org/doc/03-cli.md#outdated
Structure and explanation of version numbers
- 0.x.x is a beta version. Here every change can contain ``Breaking Changes''.
2.3.5
│ │ │
│ │ └───────── Patch (contains mostly bug fixes)
│ └─────────── Minor version (mostly functional extension)
└───────────── Major version (mostly significant change)
Rules
- Don't mix dev dependencies with dependencies in a commit
- ~ instead of ^ to have similar systems between server and dev computer and to avoid big unwanted changes during yarn update
- only run yarn update if there are only outdated packages with explicit version information
- If you don't know what belongs together, then update only one package per commit.
- Major updates are best done in your own MR with changelog entry.
Update
- Change of version number in composer.json
./scripts/composer update PACKAGENAME* --with-dependencies
Update from frontend using yarn
Manually check the version
./scripts/docker-compose run --rm client sh
yarn outdated
Manually check for security vulnerabilities
./scripts/docker-compose run --rm client sh
yarn audit
Update client
- Change the version number in
client/package.json
./scripts/docker-compose run --rm client sh
yarn PACKAGENAME
Update chat
- Change the version number in
chat/package.json
./scripts/docker-compose run --rm chat sh
yarn PACKAGENAME
Update deployer
- Change the version number in
deployer/package.json
./scripts/composer update -d deployer
Tests after every single update
./scripts/lint
for javascript and php
API
Application Programming Interface
DOM
DPP
Data Protection Policy
Draft
Non-finished work (prefix for e.g. merge requests)
DVCS
Distributed Version Control System
FOS
Friends of symfony. We use the FOSRestBundle.
json
Javascript object notation. Format for XHR and REST data transfer.
MR
Merge Request
MySQL
The database system we are using. Relational database
npm
Node.js Package Manager (package manager for javascript)
php
Hypertext Preprocessor. Server side-scripting language
PR
Pull Request
REST
REpresentational State Transfer. We use the FOSRestBundle
SQL
Structured Query Language. Language to ask a database for data
ToU
Terms of Use
VCS
Version Control System
WIP
Work In Progress (see Draft)
See also the glossary in the wiki
English term | German term | abbreviation | description |
---|---|---|---|
pick-up rate | Abholquote | The pick-up rate is visible internally for all users in the profile and represents the reliability of the food saver. In the case of not showing up for a registered pick-up and notification of this violation, the pick-up rate drops. | |
pick-up time | Abholung | Appointment at which foodsavers will pick up food at a store. | |
working groups | Arbeitsgruppen | AG | Taking care of specific tasks within foodsharing. They can be supraregional (eg AG Wiki, AG Quiz, AG graphic files), but also exist in federal states and local regions. |
store | Betrieb | Place where food is sold (eg a supermarket, a bakery, a restaurant, a farm, a canteen, a stall at a weekly market or hustle and bustle, a central warehouse) and which is or was intended for cooperation. | |
operating chain | Betriebskette | Business structure with more than 3 companies. Chains and relevant branches are only addressed in consultation with the respective Key Account Manager or the company chain group. | |
store page | Betriebsseite | Page on the foodsharing platform for a particular cooperation. Are all essential arrangements and information about a company are there. It is visible to all food servers of the company and the ambassadors. | |
store managers | Betriebsverantwortliche | BV (BIEB) | Is responsible for a cooperation. |
region | Bezirk | Smallest organizational unit for foodsavers and cooperations; responsible for all cooperations with companies located in the region. Foodsharepoints are assigned to a region. A region is organized by one or more ambassadors and may include one or more cities, counties or parts thereof. Also states are (higher) regions. | |
Ambassador | Botschafter*in | AMB / BOT | Coordinates all affairs of a region (ie also of a federal state or state): Foodsaver, cooperations, pick-ups, meetings, fair-Teiler; usually also events, press etc. |
introductory pickup | Einführungsabholung | EA | Requirement for receiving the foodsaver pass (at least 3 EA) ffter passing the quiz. The purpose of this course is to get acquainted with the progress of pick-ups in practice, to clarify open questions, and to check compliance with the rules of conduct. |
food basket | Essenskorb | Anyone can set up food baskets on the online platform to offer food for free distribution to other foodsharers or food savers. | |
Foodsharepoint | Fairteiler | FT | Place where all people (even without registration on foodsharing.de) can bring food for free and pick up. |
Foodsaver | FS | User on the online platform, who has passed the Foodsaver-Quiz and is allowed to pick up groceries at cooperative companies. | |
Foodsharer | FSh | Users on the online platform. Can offer or pick up food baskets and use foodsharepoints. | |
key account manager | KAM | Negotiated with an operating chain and represents our "face" for this chain. Communicates information between the operators and the chain. | |
Food | Lebensmittel | LM | Everything that nourishes people physically. |
local report group | Lokale Meldegruppe | LMG | Edits reports of rule violations for a region. |
Mediation team | Mediationsgruppe | MT | Can be consulted between people to help start a communication and resolve a underlying conflict. |
(local) arbitration board | (lokale) Schiedstelle | LS | Appeals against decisions on reports of rule violations. Decides on deletion of contributions in the region's forum. |
rule violation | Regelverletzung | MR | Rule violation messages are an important tool to address problems, inconsistencies and misunderstandings before they escalate into bigger conflicts. It is always preferred to first resolve things personally if it is possible. |
Mumble | Speech conference software for foodsharing conference calls on foodsharing's own Mumble server (open source, IP telephony). | ||
quiz | A prerequisite for becoming a foodsaver, company manager or ambassador. There is one quiz for each of these roles. | ||
legal agreement | Rechtsvereinbarung | A statement accepted by all the foodsavers, which contains, among other things, legal requirements for the distribution of food to private persons and releases the companies from their liability for food-to-food products. | |
sleepyhead | Schlafmütze | Virtual sign of a foodsaver that he is currently not or little active. It can be changed in your own profile. | |
verification | Verifizierung | The process of activating as foodsaver, which includes passing the foodsaver-quiz, introductory pickups, checking the personal data, and issuing of the foodsaver-passport | |
trust banana | Vertrauensbanane | On the foodsharing platform, a banana can be given by every * user * to every * other * user. It should only be given if one considers someone to be completely trustworthy as a food-saver and he / she adheres to all rules of conduct. |
About the devdocs
Feel free to provide feedback or ask questions at the #foodsharing-dev Slack channel at any time.
General information
The developer documentation (devdocs) contains general information about the foodsharing website project, step-by-step instructions, and references.
Target groups of the devdocs
The devdocs should offer everything newcomers need to start participating in the foodsharing website project.
The devdocs should also be of help to anyone that got stuck while working on the foodsharing website project and is in need of help.
Contributing to the devdocs
Anyone can contribute to the devdocs. The git project directory is called docs
.
The devdocs are based on the following principles:
- Information should be correct and current
- Information should be consistent (language, formatting,...)
- Information should be concise (but some repetition is necessary)
- Information should be complete (probably an infeasible ideal)
But don't worry too much about the last three principles.
What in, what out?
How do I decide if a specific information should be in the devdocs? Here are some principles:
- Is the information specific to foodsharing? -> Yes
- Were you surprised about it? -> Yes
- Is the information general enough to be explained in a foodsharing-independent tutorial or documentation? -> No, include a link
- Is the information specificly about one piece of code and only interesting during reading this code (and not for finding this piece of code)? -> No, explain the code with comments in the code.
Markdown
The devdocs are written in Markdown (md).
For more info please see Documentation.
Local setup
The current devdocs available via localhost:3000
in your browser.
The devdocs are built at every change on the master branch and published here.
The gitlab ci is not triggered if you push with the option git push -o ci.skip
.
This is useful if you work on the devdocs since they are only built on master anyway.
mdbook
The devdocs are built with mdbook.
Contributors
💻 = Code 📝 = Documentation 🎨 = Design 🐜 = Bug reports 💡 = Ideas, Planning, & Feedback 🔐 = Security 🔩 = Infrastructure (Hosting, Build-Tools, etc) 👀 = Reviewed Pull Requests 💬 = Answering Questions 🏢 = Board member
💻 Emilia Paz |
💻 Jannis R |
💻 Michael Aydinbas |
💻 📝 Valentin |
💻 Valentin |
💻 Theo |
🐜 💻 🎨 Michael Paul Killian |
💻 Basti A. |
🐜 💻 📝 Christian |
💻 📝 Felix |
🐜 💡 Boji |
🐜 💡 🔐 irgendwer |
💻 Raphael |
💻 Timo Hartmann |
💻 📝 🔩 👀 Nick Sellen |
🏢 🐜 💻 💡 💬 fs_k |
💻 D0nPiano |
💻 Nigel Green |
🏢 🐜 💻 💡 💬 Johannes |
💻 Adrian Heine |
💻 📝 Thomas Pfeiffer |
🐜 💻 💡 💬 👀 Peter Tönnies |
💻 Jano |
💻 👀 Tilmann Becker |
💻 🔩 👀 Matthias Larisch |
💻 👀 🔐 chandi |
💻 💡 djahnie |
📝 Jana Aydinbas |
🏢 💡 Manuel Wiemann |
🎨 💡 mel |
💻 Peter Reutlingen |