You have worked through the first seven lessons learning tools: you set up the environment, wrote your first program, and got to know the syntax, the types, the operators and the conversions. Marta, Iván and Lucía turned up in every example, along with a few tasks with a title, a priority and estimated hours. It is time to formally introduce the project that runs through the entire course: what Taller Nómada is, what problem it has, what application you are going to build to solve it, what the canonical data model is that you will use across the eleven modules, and which part you will build in each one. This lesson is the map of the whole journey.

Contents

  1. Taller Nómada: the context
  2. The problem to be solved
  3. The team: Marta, Iván and Lucía
  4. What Nómada Tasks will do
  5. The canonical data model of a task
  6. The reference example object
  7. The project's business rules
  8. Course map: what each module builds
  9. The file structure that will keep growing
  10. Common Mistakes and Tips
  11. Exercises
  12. Conclusion

  1. Taller Nómada: the context

Taller Nómada is a small coworking space and creative workshop housed in a refurbished warehouse. It is a completely fictional company, created for this course, with equally fictional data.

Its business has two legs:

  • Coworking: twelve permanent desks and a multipurpose room rented out by the hour for meetings and presentations.
  • Creative workshop: a space equipped for screen printing, bookbinding and light carpentry, where courses are taught and residents' projects are hosted.

The business works, but internal management does not. And that is our starting point.

  1. The problem to be solved

Today, work at Taller Nómada is organized like this:

  • A wall of sticky notes with the tasks in progress.
  • A messaging group where things get agreed and nobody writes them down.
  • A shared spreadsheet that nobody has updated since March.

The consequences are exactly what you would expect:

Symptom Real consequence
Notes fall off or come unstuck Tasks disappear and nobody notices
Nobody knows who is doing what Duplicated work and work left undone
The due dates live in Marta's head They are discovered late, every time
There is no history It is impossible to know how long something similar took
There is no view of workload Iván is juggling three projects while Lucía's schedule is empty

What they need is not a corporate tool with a thousand options. They need something small, fast and theirs: a shared task list that shows who is doing what, with what priority and by when.

That is Nómada Tasks, and you are the one who is going to build it.

  1. The team: Marta, Iván and Lucía

Three people who will be the cast of every example and exercise in the course.

Person Role What they need from the application
Marta Coordinator Seeing the overall status, spreading the workload, keeping an eye on due dates
Iván Designer Seeing only his own tasks, sorted by urgency, and marking them as done
Lucía Developer Filtering by tag, estimating hours and checking the history

Their needs are not the same, and that is deliberate: it will force you to think about filters, sorting and different views over the same data.

  1. What Nómada Tasks will do

The full scope of the application, in roughly the order it will be built:

  1. Creating tasks with all their fields, validating the input data.
  2. Assigning them to someone on the team (or leaving them unassigned).
  3. Changing their status between pending, in-progress and done.
  4. Editing and deleting existing tasks.
  5. Filtering by assignee, status, priority or tag.
  6. Sorting by due date, priority or estimated hours.
  7. Calculating metrics: workload per person, progress percentage, overdue tasks.
  8. Displaying everything in a usable web interface.
  9. Persisting the data in the browser so it is not lost on reload.
  10. Synchronizing with a remote API.
  11. Testing the application with automated tests.
  12. Optimizing and deploying the final version.

None of this happens in one go. Each module of the course adds a layer.

  1. The canonical data model of a task

Here is the heart of the project. This table is the official reference for the whole course: every time a task appears in any lesson, it will have exactly these fields with these types.

Field Type Allowed values Required Example
id number A unique positive integer Yes 1
title string Non-empty text, 1-100 characters Yes 'Redesign the multipurpose room'
assignee string | null 'Marta', 'Iván', 'Lucía' or null No 'Iván'
priority string 'high', 'medium', 'low' Yes 'high'
status string 'pending', 'in-progress', 'done' Yes 'in-progress'
tags string[] An array of strings; it can be empty Yes (it may be []) ['design', 'space']
estimatedHours number Greater than 0, at most 40 Yes 12
dueDate string ISO format 'yyyy-mm-dd' Yes '2026-09-30'

5.1 Why each field is the way it is

id is a number, not text. It is a sequential identifier assigned by the application. Being numeric, generating the next one is trivial.

assignee can be null. Here we apply what we learned in Variables and Data Types: null means "deliberately unassigned". We do not use '' or undefined. A task with no assignee is a legitimate business state: Marta creates the task first and decides who does it afterwards.

priority and status are strings from a closed set. We could use numbers (1, 2, 3), but 'high' reads and debugs infinitely better than 1. The price is having to validate that the value is one of the allowed ones, something you already know how to do with ===.

tags is always an array, never null. If a task has no tags, the value is []. This is an important design decision: it guarantees that all the code downstream can do task.tags.length without checking anything first. And remember from Type Conversion and Comparisons: an empty array is truthy, so you have to check its length, not its existence.

estimatedHours allows decimals. Half an hour is a reasonable unit (7.5). The maximum of 40 corresponds to a full working week.

dueDate is an ISO string, not a Date object. This is probably the most debatable decision in the project, and it is deliberate for three reasons:

  1. It sorts itself. '2026-09-30' < '2026-11-05' is true, because the alphabetical order of the ISO format matches the chronological order.
  2. It is stored and transmitted without conversions. Neither browser storage nor a JSON API handles Date objects: they turn them into text anyway.
  3. It avoids time-zone traps, which are numerous and unpleasant for someone starting out.

We will work with dates as text throughout the course, and we will only use Date objects when we need to calculate differences between dates.

5.2 The statuses and their life cycle

A task always follows this path:

stateDiagram-v2
    [*] --> pending: Marta creates it
    pending --> in_progress: someone starts it
    in_progress --> done: it is finished
    in_progress --> pending: it is parked
    done --> in_progress: it needs touching up
    done --> [*]

Only those transitions are valid. A task cannot go straight from pending to done: someone has to have started it. You will implement this rule in Module 2, when you learn about conditionals.

  1. The reference example object

This is the object that will come back again and again throughout the course. You have not studied object syntax yet —that is Introduction to Objects— but you can read it perfectly well: it is a grouping of the same eight variables you already know how to declare.

// The reference task for Nómada Tasks.
// Each line is a field of the canonical model.
const exampleTask = {
  id: 1,
  title: 'Redesign the multipurpose room',
  assignee: 'Iván',
  priority: 'high',
  status: 'in-progress',
  tags: ['design', 'space'],
  estimatedHours: 12,
  dueDate: '2026-09-30'
};

And here is the same set of data expressed with what you can do today: separate variables.

'use strict';

// --- Task 1: the same data, in independent variables ---------------
const id1 = 1;
const title1 = 'Redesign the multipurpose room';
const assignee1 = 'Iván';
const priority1 = 'high';
let status1 = 'in-progress';
const tags1 = ['design', 'space'];
const estimatedHours1 = 12;
const dueDate1 = '2026-09-30';

console.log(`[${id1}] ${title1} — ${assignee1} (${priority1})`);

Compare the two versions. With one task, separate variables are manageable. With three, you are already numbering your variables (title1, title2, title3), which is an unmistakable sign that a structure is missing. With forty tasks, it would be unworkable.

That discomfort is intentional: you will feel it in the final exercise of this lesson, and it is exactly the motivation for the objects and arrays of Module 4.

  1. The project's business rules

Beyond the data model, the project has a set of fixed rules that will apply throughout the course:

Rule Description
R1 The id is unique and sequential; the application assigns it, never the user
R2 The title cannot be empty or contain only spaces
R3 estimatedHours must be greater than 0 and no more than 40
R4 dueDate cannot be earlier than the creation date
R5 A new task is always born with the status 'pending'
R6 Only the status transitions in the diagram above are permitted
R7 Nobody can exceed 40 estimated hours assigned in the same week
R8 A task with no assignee has assignee: null, never ''
R9 Tags are stored in lowercase and without duplicates
R10 An overdue task (dueDate in the past and a status other than 'done') is highlighted

These rules will appear progressively. In this module you have already applied R2, R3 and R8 without knowing it, when you validated the form in the previous lesson.

  1. Course map: what each module builds

This diagram shows which part of Nómada Tasks each module builds and how they lean on one another.

flowchart TD
    M1["Module 1 · Fundamentals<br/>A task's data<br/>in variables and types"]
    M2["Module 2 · Control flow<br/>Validating statuses and going<br/>through several tasks"]
    M3["Module 3 · Functions<br/>createTask, validateTask,<br/>calculateWorkload"]
    M4["Module 4 · Objects and arrays<br/>The task as an object<br/>and the task list"]
    M5["Module 5 · Advanced<br/>The Task class, modules<br/>and asynchrony"]
    M6["Module 6 · DOM<br/>The interface: list,<br/>form and events"]
    M7["Module 7 · APIs<br/>Saving in the browser<br/>and syncing with the API"]
    M8["Module 8 · Testing<br/>Debugging and testing<br/>all the logic"]
    M9["Module 9 · Performance<br/>Keeping it responsive<br/>with many tasks"]
    M10["Module 10 · Frameworks<br/>What it would look like with<br/>React, Vue or Angular"]
    M11["Module 11 · Final project<br/>Nómada Tasks,<br/>complete and deployed"]

    M1 --> M2 --> M3 --> M4 --> M5 --> M6 --> M7 --> M8 --> M9 --> M10 --> M11

In more detail, module by module:

Module What you build in Nómada Tasks
1. Introduction A task's data in variables of the right type; basic form validation
2. Control structures Deciding the priority, validating status transitions, going through several tasks, catching errors
3. Functions Grouping the logic: createTask(), isValidTask(), calculateWorkload(), formatSummary()
4. Objects and arrays The task as an object and the full list as an array; filtering, sorting and aggregating with filter, sort and reduce
5. Advanced A Task class with encapsulated validation; splitting the code into modules; loading data asynchronously
6. The DOM The real interface: painting the list, the creation form, the status buttons, the filters
7. Browser APIs Saving to localStorage so the data is not lost; syncing with an API through fetch
8. Testing Debugging with the DevTools; unit tests of the task logic with Jest; end-to-end tests with Cypress
9. Performance Keeping the list smooth with hundreds of tasks; efficient rendering
10. Frameworks What the same task list would look like in React, Vue and Angular
11. Final project Assembling, polishing, testing and deploying the complete application

One important note on how to read this map: each module rewrites part of the previous work with better tools. Today's eight separate variables will become an object in Module 4 and a class instance in Module 5. It is not that today's approach is wrong: it is that you learn the scaffolding before the building.

  1. The file structure that will keep growing

In the lesson Setting Up Your Development Environment you created this:

nomada-tasks/
├── index.html
├── css/
│   └── styles.css
└── js/
    └── app.js

This is how it will look by the end of the course:

nomada-tasks/
├── index.html
├── css/
│   └── styles.css
├── js/
│   ├── app.js              ← entry point
│   ├── model/
│   │   ├── task.js         ← the Task class (Module 5)
│   │   └── validation.js   ← rules R1-R10 (Modules 2-3)
│   ├── data/
│   │   ├── store.js        ← localStorage (Module 7)
│   │   └── api.js          ← fetch to the API (Module 7)
│   ├── view/
│   │   ├── list.js         ← rendering the list (Module 6)
│   │   ├── form.js         ← creating and editing (Module 6)
│   │   └── filters.js      ← filters and sorting (Module 6)
│   └── util/
│       └── dates.js        ← date helpers (Module 3)
├── test/
│   └── task.test.js        ← tests with Jest (Module 8)
└── package.json            ← dependencies (Module 8)

You do not need to create any of this now. It is shown so that you can see where you are heading and understand the logic of the organization: the model (what a task is and what rules it obeys), the data (where it comes from and where it is stored), the view (how it is displayed) and the utilities. That separation into layers is a design principle that applies to projects of any size.

Common Mistakes and Tips

Common mistakes when tackling a long project

  • Wanting to build it all at once. The natural impulse is to open the editor and start with the interface. It does not work: without validated logic behind it, the interface only hides the problems.
  • Changing the data model as you go. If in Module 4 you decide to call assignee owner, none of the later examples will fit any more. Stick to the table in section 5 throughout the course.
  • Skipping the project and doing only the standalone exercises. What consolidates the learning is the thread: seeing the same problem solved better every time you learn something new.
  • Using '' instead of null for an unassigned task. It breaks R8 and leads to inconsistent checks all over the code.
  • Storing dates in dd/mm/yyyy format. They can no longer be sorted as text and everything else gets harder.
  • Getting frustrated because today's code is "primitive". Eight separate variables for one task are awkward, and they are meant to be: that awkwardness is what gives meaning to what you will learn next.

Tips

  • Keep this lesson handy. The data model table is the reference you will come back to across all eleven modules.
  • Create a folder per module inside the project while you practice (practice/module-01/), and keep js/ for the final code.
  • Make a Git commit at the end of each module. You will see your progress and be able to go back.
  • Whenever you learn something new, ask yourself: "which part of Nómada Tasks does this improve?" It is the best way to make a concept stick.
  • Invent your own tasks for the Taller Nómada team. The more you play with the data, the more natural the domain will feel.
  • Do not run ahead. If a later module tempts you, resist: the order is designed so that each piece rests on the previous one.

Exercises

Exercise 1: Validate three tasks against the model

For each of these three proposed tasks, state which rules of the data model or of section 7 it breaks and how you would fix it:

Task A

id: '3'
title: '   '
assignee: ''
priority: 'urgent'
status: 'pending'
tags: null
estimatedHours: 0
dueDate: '15/10/2026'

Task B

id: 4
title: 'Screen-printing storeroom inventory'
assignee: 'Lucía'
priority: 'low'
status: 'done'
tags: ['Workshop', 'workshop', 'INVENTORY']
estimatedHours: 55
dueDate: '2026-12-01'

Task C

id: 5
title: 'Prepare the open day'
assignee: null
priority: 'high'
status: 'in-progress'
tags: []
estimatedHours: 9.5
dueDate: '2026-11-20'

Exercise 2: Three tasks and a summary

Write a script that declares three Taller Nómada tasks using only what you have learned in this module (variables, types, operators, conversions, template literals). No objects, no arrays of objects, no functions and no loops.

The three tasks:

Field Task 1 Task 2 Task 3
id 1 2 3
title Redesign the multipurpose room Signage for the screen-printing workshop Update the bookings website
assignee Iván Marta Lucía
priority high medium high
status in-progress pending pending
tags design, space design, communication web, development
estimatedHours 12 6 14
dueDate 2026-09-30 2026-10-15 2026-10-02

The script has to print:

  1. A header with the name of the project.
  2. One summary line per task in this format: [1] Redesign the multipurpose room · Iván · high · in-progress · 12 h · due 2026-09-30
  3. The team's total estimated hours.
  4. The average hours per task, rounded to one decimal place.
  5. How many tasks are high priority.
  6. The task with the nearest due date (comparing the ISO dates as text).
  7. A warning with console.warn if the total exceeds 30 hours.

Exercise 3: Reflect on the model

Answer each question with reasoning, in three or four lines:

  1. Why is tags always an array ([] when it is empty) instead of null? What problem does that decision avoid, given what you know about truthy values?
  2. What concrete advantage does storing dueDate as '2026-09-30' give over '30/09/2026'?
  3. While writing exercise 2 you will have felt a certain awkwardness. What exactly is it, and what do you think will solve it?

Solutions

Exercise 1

Task A — breaks seven rules:

Field Problem Fix
id: '3' It is a string; it has to be a number id: 3
title: ' ' Spaces only: empty after trim() (R2) A real title
assignee: '' It has to be null if there is no assignee (R8) assignee: null
priority: 'urgent' Not one of the three allowed values priority: 'high'
tags: null It must always be an array tags: []
estimatedHours: 0 It has to be greater than 0 (R3) estimatedHours: 4
dueDate: '15/10/2026' Not in ISO format dueDate: '2026-10-15'

Task B — breaks two rules:

  • estimatedHours: 55 exceeds the maximum of 40 (R3). If the work really is 55 hours, it has to be split into several tasks: that is exactly what the rule is designed to force.
  • tags: ['Workshop', 'workshop', 'INVENTORY'] breaks R9 twice over: there is uppercase and there is a duplicate ('Workshop' and 'workshop' are the same tag once normalized). The correct value would be ['workshop', 'inventory'].

Task Cit is valid. It is worth going over why each questionable field is fine:

  • assignee: null is correct: the task exists but has not been assigned yet (R8).
  • tags: [] is correct: an empty list, not null.
  • estimatedHours: 9.5 is correct: the field allows decimals and this is within range.
  • status: 'in-progress' with assignee: null is odd from a business point of view (someone has started it but there is no record of who), yet it breaks no written rule. It is exactly the kind of detail you discover while building, and that in a real project would lead to adding a new rule.

Exercise 2

'use strict';

// ===================================================================
// Nómada Tasks · Module 1 · Summary of the Taller Nómada tasks
// Using only variables, operators and template literals.
// ===================================================================

// --- Task 1 --------------------------------------------------------
const id1 = 1;
const title1 = 'Redesign the multipurpose room';
const assignee1 = 'Iván';
const priority1 = 'high';
let status1 = 'in-progress';
const tags1 = 'design, space';
const estimatedHours1 = 12;
const dueDate1 = '2026-09-30';

// --- Task 2 --------------------------------------------------------
const id2 = 2;
const title2 = 'Signage for the screen-printing workshop';
const assignee2 = 'Marta';
const priority2 = 'medium';
let status2 = 'pending';
const tags2 = 'design, communication';
const estimatedHours2 = 6;
const dueDate2 = '2026-10-15';

// --- Task 3 --------------------------------------------------------
const id3 = 3;
const title3 = 'Update the bookings website';
const assignee3 = 'Lucía';
const priority3 = 'high';
let status3 = 'pending';
const tags3 = 'web, development';
const estimatedHours3 = 14;
const dueDate3 = '2026-10-02';

// --- Calculations ---------------------------------------------------

// Total hours
const totalHours = estimatedHours1 + estimatedHours2 + estimatedHours3;

// Average rounded to one decimal: multiply by 10, round and divide
const TASK_COUNT = 3;
const averageHours = Math.round((totalHours / TASK_COUNT) * 10) / 10;

// High-priority tasks: each comparison is true (1) or false (0)
const highPriorityTasks =
  Number(priority1 === 'high') +
  Number(priority2 === 'high') +
  Number(priority3 === 'high');

// The nearest date: ISO dates are compared as text
const earliestSoFar = dueDate1 < dueDate2 ? dueDate1 : dueDate2;
const earliestDate = earliestSoFar < dueDate3 ? earliestSoFar : dueDate3;

// The title matching that date
const mostUrgentTitle =
  earliestDate === dueDate1 ? title1 :
  earliestDate === dueDate2 ? title2 :
                              title3;

// --- Output ----------------------------------------------------------
console.log('=========================================');
console.log(' NÓMADA TASKS · Taller Nómada');
console.log('=========================================');

console.log(
  `[${id1}] ${title1} · ${assignee1} · ${priority1} · ${status1} · ${estimatedHours1} h · due ${dueDate1}`
);
console.log(
  `[${id2}] ${title2} · ${assignee2} · ${priority2} · ${status2} · ${estimatedHours2} h · due ${dueDate2}`
);
console.log(
  `[${id3}] ${title3} · ${assignee3} · ${priority3} · ${status3} · ${estimatedHours3} h · due ${dueDate3}`
);

console.log('-----------------------------------------');
console.log(`Total estimated hours:   ${totalHours} h`);
console.log(`Average per task:        ${averageHours} h`);
console.log(`High-priority tasks:     ${highPriorityTasks} of ${TASK_COUNT}`);
console.log(`Due soonest:             ${mostUrgentTitle} (${earliestDate})`);

const WARNING_LIMIT = 30;
totalHours > WARNING_LIMIT &&
  console.warn(`Warning: the team has ${totalHours} h estimated in total.`);

Output:

=========================================
 NÓMADA TASKS · Taller Nómada
=========================================
[1] Redesign the multipurpose room · Iván · high · in-progress · 12 h · due 2026-09-30
[2] Signage for the screen-printing workshop · Marta · medium · pending · 6 h · due 2026-10-15
[3] Update the bookings website · Lucía · high · pending · 14 h · due 2026-10-02
-----------------------------------------
Total estimated hours:   32 h
Average per task:        10.7 h
High-priority tasks:     2 of 3
Due soonest:             Redesign the multipurpose room (2026-09-30)
⚠ Warning: the team has 32 h estimated in total.

Techniques from this module that show up here:

  • Number(priority === 'high') converts a boolean into 1 or 0 so the results can be added up. It is a direct application of the explicit conversion from Type Conversion and Comparisons.
  • Math.round(x * 10) / 10 rounds to one decimal without using toFixed, which would return a string.
  • Comparing ISO dates as text works because alphabetical order matches chronological order.
  • The chained ternaries pick the earliest date and its associated title.
  • The && short-circuit fires the warning only when the threshold is exceeded.

Exercise 3

1. Why is tags always an array?

Because it lets all the downstream code treat the field the same way, with no preliminary checks: tags.length always works, whether there are three tags or none at all. If the value were null when empty, every place that read the field would first have to ask whether it exists, and forgetting to do so would cause a TypeError. On top of that, as you learned in the previous lesson, an empty array is truthy, so if (tags) does not tell a full list apart from an empty one: the correct check is always tags.length === 0, and that check is only possible if the field is always an array.

2. What advantage does the ISO format give?

That its alphabetical order matches its chronological order, because the components go from largest to smallest magnitude (year, month, day) and are zero-padded. That lets you sort and compare dates with the < and > operators without any conversion or library, exactly as done in exercise 2. With '30/09/2026' the text comparison would be nonsense: '30/09/2026' < '15/10/2026' would be false, because it would be comparing '3' with '1'. The ISO format is also the international standard, the one JSON APIs use and the one the browser's <input type="date"> field expects.

3. What awkwardness did you feel?

That each task needs eight numbered variables (title1, title2, title3...), and that any calculation over the whole set —adding up hours, counting priorities, finding the most urgent— has to be written by manually repeating all three cases. With three tasks it is tedious; with forty it would be impossible. Two things are missing: a way to group a task's eight fields into a single unit (objects, Module 4), a way to group all the tasks into a single collection (arrays, Module 4), and a way to repeat an operation over all of them without copy-pasting (loops, Module 2). That need, felt first-hand, is exactly why those tools exist.

Conclusion

You now know the whole project. You know what Taller Nómada is, what its real problem is and what Marta, Iván and Lucía need from the application. You have the canonical data model of a task, with its eight fields, its types and its allowed values, and you understand the design decisions behind it: why assignee can be null, why tags is always an array and why dueDate is text in ISO format. You know the ten business rules you will implement along the way, the life cycle of a task, the map of what each module builds and the file structure you are working toward.

With that, you close Module 1. You started without having written a single line of JavaScript and you finish with a development environment set up, a project underway and the ability to declare, calculate, convert and compare the data of a real task. That is no small thing.

But you have finished the module with a very specific and very productive frustration: you can describe three tasks, but you cannot decide or repeat. You do not know how to make the program check for itself whether a status transition is valid, nor how to go through a list of forty tasks without writing the same thing forty times. All your code runs top to bottom, in a straight line, without making a single decision.

That changes in Module 2: Control Structures. You will start with Conditional Statements, where you will learn to make the program pick one path or another —classifying a task's priority, detecting whether it is overdue, allowing or rejecting a status change—, and you will move on to loops, which will let you apply that logic to all of Taller Nómada's tasks at once. It is the moment when your code stops being a list of instructions and starts behaving like a program.

JavaScript Course: From Beginner to Advanced

Module 1: Introduction to JavaScript

Module 2: Control Structures

Module 3: Functions

Module 4: Objects and Arrays

Module 5: Advanced Objects and Functions

Module 6: The Document Object Model (DOM)

Module 7: Browser APIs and Advanced Topics

Module 8: Testing and Debugging

Module 9: Performance and Optimization

Module 10: JavaScript Frameworks and Libraries

Module 11: Final Project

© Copyright 2026. All rights reserved