Drive Calendar
Drive Calendar is a custom-built application designed to automatically synchronize my driving lesson schedule with my digital calendar. The primary objective was to ensure I never missed a lesson while also tracking my progress across key driving skills such as steering, braking, and anticipation.
This project was inspired by my grandmother, who was a constant source of support throughout my driving journey. She loved staying updated on my lessons and progress, which motivated me to develop an easy-to-share tool for both myself and my loved ones.
Project Overview
The driving school's online dashboard was divided into two separate pages: one displaying upcoming lessons, and another detailing skill progression evaluations provided by the instructor after each lesson.
Data Extraction Approach
To retrieve this information, I developed a backend service that fetches both pages and parses their content using cheerio, a fast and flexible HTML parser for Node.js.
By spoofing the user-agent header to mimic a mobile device, I accessed simplified mobile versions of these pages, which significantly streamlined the scraping process.
Lesson Schedule
From the schedule page, I extracted all upcoming lessons, including timestamps and lesson numbers. This data was transformed into a structured JSON format:
[
{ lesson: 1, start: 1692606000, end: 1692609600 },
{ lesson: 2, start: 1692692400, end: 1692696000 },
// ...
]
To create the live .ics calendar feed, I used
ical-generator, a
Node.js library that
makes it simple to build and serve iCalendar files programmatically for integration with Google Calendar, Apple
Calendar, and Outlook.
Calendar Integration Endpoints
To facilitate easy subscription, I implemented dedicated backend routes that redirect users directly to their preferred calendar service's import page, preloaded with the correct calendar feed URL:
app.get("/calendar/add/google", (req, res) => {
res.redirect(`https://calendar.google.com/calendar/u/0/r?cid=webcal://${BASE_URL}/calendar.ics`);
});
app.get("/calendar/add/outlook/office", async (req, res) => {
res.redirect(`https://outlook.office.com/calendar/addfromweb?url=https://${BASE_URL}/calendar.ics&name=Dinands Rijlessen`);
});
app.get("/calendar/add/outlook/live", async (req, res) => {
res.redirect(`https://outlook.live.com/calendar/addfromweb?url=https://${BASE_URL}/calendar.ics&name=Dinands Rijlessen`);
});
app.get("/calendar/add/apple", async (req, res) => {
res.redirect(`webcal://${BASE_URL}/calendar.ics`);
});
Skill Progression Tracking
From the progression page, I parsed detailed skill evaluations entered by the driving instructor after each lesson. These included metrics like braking, anticipation, and clutch control, each rated on a numeric scale.
The data structure I used to represent this was:
[
{
fase: "Traffic Participation",
bases: [
{ base: "Steering", level: 6 },
{ base: "Braking", level: 5 },
{ base: "Anticipation", level: 4 },
]
},
{
fase: "Vehicle Control",
bases: [
{ base: "Clutch Control", level: 7 },
{ base: "Hill Start", level: 6 }
]
}
]
Selecting appropriate naming conventions was a challenge. After considering terms like “skills,” “competencies,” and
“metrics,” I adopted fase and base to stay consistent with the driving school's original
terminology.
Below is a snapshot of how this progression data is displayed within the app interface:
Technology Stack
- Node.js — Backend JavaScript runtime
- Express — Web framework for Node.js
- Cheerio — Fast, flexible HTML parsing for scraping
- ical-generator — Programmatic iCalendar feed creation
- JavaScript (ES6+) — Core language used throughout
- HTML/CSS — Frontend markup and styling
Through this project, I gained valuable experience in web scraping, integrating external applications, and designing solutions with empathy. Ultimately, creating something simple yet meaningful for someone I care about was the most rewarding outcome.