POD (placement online diary) is an application to allow students to keep track of their placement year.
POD is a website that makes life easier for students on their year in industry, it does this by allowing users to to keep a detailed record of what happens during their YII, they can then refer back to this information when creating CV's and end of year reports etc
The way in which users recount information into the website is through the use of 'entries', the user can create as many entries as they like and each entry can be formed from a single 'template'
When creating an entry, a user selects a certain template to use. This template contains a pre-defined set of inputs for the user to fill in, some examples of templates are...
- General: For creating a general diary entry
- Training: For when the user has completed some training
- New skill: For when the user learns a new skill
say the user selects the "New skill" template, they would be presented with inputs to fill in related to learning a new skill, these would include...
- The name of the skill they learned (text input)
- The date they learned that skill (date input)
- Details on what they learned or how they learned the skill (text-area input)
When developing a new template a few criteria must be met in order for it to work correctly with the application, Templates are stored in MongoDB to allow them to have flexible schemas.
Templates are stored as JSON, for example, the "General" template is defined as follows...
{
"_id": {
"$oid": "63fb3b3a0a0c8ed50908f892"
},
"name": "General",
"description": "A normal diary entry",
"icon": "general.svg",
"fields": [
{
"id": "title",
"label": "Entry title",
"type": "text",
"required": true,
"validation": [
"required",
"max:100"
]
},
{
"id": "date",
"label": "Date",
"type": "date",
"required": true,
"validation": [
"required",
"date"
]
},
{
"id": "content",
"label": "Entry content",
"type": "textarea",
"required": true,
"validation": [
"required",
"max:3000"
]
}
],
"updated_at": {
"$date": {
"$numberLong": "1677409082055"
}
},
"created_at": {
"$date": {
"$numberLong": "1677409082055"
}
}
}
Templates contain the following top level attributes...
Key | Description | Type | Required? |
---|---|---|---|
_id | A unique identifier for this template, this should be automatically generated by MongoDB | Int | yes |
name | A string representing the name of the template | String | yes |
icon | The filename of the icon for this template (this needs to be stored in the applications /assets/images/templates folder) | String | no |
description | A string representing the description of the template | String | yes |
fields | An array of the fields this template contains | Array | yes |
Fields is an array of the inputs this template will provide for the user. This array MUST have a field with an id of title
{
"fields": [
...
{
"id": "title",
"label": "Entry title",
"type": "text",
"required": true,
"validation": [
"required",
"max:100"
]
}
]
}
and each field consists of the following options
Key | Description | Type | Options | Required? |
---|---|---|---|---|
id | A unique identifier for this field | String | yes | |
label | What the user sees on the screen when filling in this input | String | yes | |
type | What type of input this is, these must be implemented in the application, currently there are a few built in | String | text, date, textarea | yes |
required | Is this input required? (used for front end validation) | Boolean | true, false | no |
validation | An array of validation rules used to validate this input on the back-end | Array | A list of Laravel validaion rules can be found here | yes |
An important part of the project is measuring the most effective gamification techniques in online diary applications, these gamification techniques are implemented as features in the application.
Some examples of features include...
- A leader-board to view the status of other students
- A streak of the number of consecutive entries made by the user
These features can then be grouped together to create a series of gamification features for different users.
As mentioned above, these features can be grouped together, these are known as feature-groups a feature group contains a number of users and a number of features.
Users are then randomly assigned into a feature group when they sign up for the site.
User feedback is integrated into the application, feedback is a feature in itself so can be toggled using the active
column in the features
table
Users can fill in feedback by navigating to the feedback page where they will be presented with a form of entirely optional questions to answer, only the questions the user answers will be saved to the database.
The reason for integrating feedback into the application was to allow a dynamic feedback form to be displayed to the users. Depending on the features the user has access to, different forms will be presented to them, allowing for a much more tailored feedback experience for the users.
The questions for feedback are stored in database/seeders/core/FeedbackSeeder.php
In order to create a question, it must have an associated FeedbackGroup
which is the group of questions it belongs to on the form, think of this as a section of a form, i.e "General questions"
$general = FeedbackGroup::create([
"name" => "General",
"caption" => "Some general questions about the app",
"position" => 0,
]);
Here is an example of seeding a feedback group, all three fields are required and are explained below...
Field | Description |
---|---|
name | The name of this group, this will be displayed on screen |
caption | A small piece of text to explain the types of questions in this group,this will be displayed on scren |
position | The position of this group on the screen (starting from 0 at the top) |
FeedbackQuestion::create([
"name" => "How would you rate this application?",
"feedback_group_id" => $general->id,
"question_type" => "radio",
"data" => [
"options" => [
["label" => "Fantastic", "id" => "fantastic"],
["label" => "Good", "id" => "good"],
["label" => "Ok", "id" => "ok"],
["label" => "Poor", "id" => "poor"],
]
]
]);
This example illustrates creating a new feedback question for the user that asks them to review the application from a series of radio buttons.
We can also target certain features when creating feedback questions using the following syntax...
FeedbackQuestion::create([
"name" => "Did you enjoy using the leaderboard feature?",
"feedback_group_id" => $featureGroup->id,
"question_type" => "radio",
"targeted" => true, // Note the targeted attribute set to true
"data" => [
"options" => [
["label" => "Yes", "id" => "yes"],
["label" => "No", "id" => "no"],
],
"feature_id" => Feature::where("name", "=", "leaderboard")->firstOrFail()->id
]
]);
Below explains all the available attributes for a feedback question...
Field | Description |
---|---|
name | The name of this question to be displayed on screen |
feedback_group_id | The id of the feedback group this question belongs to |
question_type | The type of question this is, currently the available options are text , radio |
targeted (optional) | Does this question target a specific feature? true or can be missed |
data | An array of additional attributes that are needed for particular configurations (see below) |
Certain data attributes are required for particular configrations...
- if
targeted
istrue
thendata.feature_id
will need to contain a list of id's to target, - if
targeted
istrue
then you will need to specify anoperator
field which indicates how the array ofdata.feature_id
should be handled...- An operator of
all
will mean that all user will need to match all the features specified in the array - An operator of
any
will mean the user can view the question if they have any feature in the array - If an operator is not specified the default will be
all
- An operator of
- if
question_type
isradio
then a list of options will need to be present indata.options
, each option needs a display label and a unique id.
Clone the project
git clone git@github.com:angus-websites/pod.git
Go to the project directory
cd pod
Setup Laravel Sail
NOTE: Ensure you have Docker installed
docker run --rm \
-u "$(id -u):$(id -g)" \
-v $(pwd):/var/www/html \
-w /var/www/html \
laravelsail/php81-composer:latest \
composer install --ignore-platform-reqs
Generate a .env file
cp .env.example .env
Run Laravel Sail (Development server)
./vendor/bin/sail up
Open a new Terminal tab in the same project root folder
Generate an app encryption key
./vendor/bin/sail php artisan key:generate
Migrate the database
./vendor/bin/sail php artisan migrate
The project has two main seeding classes DevSeeder
as well as the default DatabaseSeeder
, DevSeeder
will seed a bunch of example users and is meant for development purposes, to run this seeder run the following command...
./vendor/bin/sail php artisan db:seed --class=DevSeeder
DatabaseSeeder
seeds only essential data and is meant for a production server.
Install npm dependencies
./vendor/bin/sail npm install
Run Vite
./vendor/bin/sail npm run dev
Visit Localhost
Tests are located in the tests
directory and can be run from the command line...
./vendor/bin/sail php artisan test
When updating certain fields in the .env
file when using Laravel Sail, you may need to restart the Docker container for changes to take affect.
A live version of POD is available here
Client: Vue.js, InertiaJS, TailwindCSS
Server: PHP (Laravel framework)
Database: MYSQL, MongoDB