<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Javier Andre Neira Machaca</title>
    <description>The latest articles on DEV Community by Javier Andre Neira Machaca (@draylexter).</description>
    <link>https://dev.to/draylexter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2318003%2F4d4b40bb-bcbf-4ae1-a233-c36f1a33a07c.png</url>
      <title>DEV Community: Javier Andre Neira Machaca</title>
      <link>https://dev.to/draylexter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/draylexter"/>
    <language>en</language>
    <item>
      <title>Building an App with a Cloud NoSQL Server Database</title>
      <dc:creator>Javier Andre Neira Machaca</dc:creator>
      <pubDate>Wed, 18 Dec 2024 05:16:02 +0000</pubDate>
      <link>https://dev.to/draylexter/building-an-app-with-a-cloud-nosql-server-database-164m</link>
      <guid>https://dev.to/draylexter/building-an-app-with-a-cloud-nosql-server-database-164m</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The proliferation of cloud technologies has made it easier than ever to build scalable, efficient, and reliable applications. Choosing a database is one of the most critical decisions in app development, especially when working with modern applications that require high scalability and flexibility. In this article, we will explore how to build an application with a cloud NoSQL database, excluding DynamoDB and CosmosDB. We'll use Couchbase, a powerful NoSQL database, as an example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Choose a NoSQL Database?
&lt;/h2&gt;

&lt;p&gt;NoSQL databases are designed to handle unstructured or semi-structured data efficiently. They are ideal for applications with high scalability requirements, such as social networks, IoT platforms, and real-time systems. Key advantages of NoSQL databases include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scalability: Horizontal scaling ensures that the database can handle increased workloads.&lt;/li&gt;
&lt;li&gt;Flexibility: Schema-less design allows for rapid iteration during development.&lt;/li&gt;
&lt;li&gt;Real-time Processing: Many NoSQL databases support real-time data synchronization.
## What is Couchbase?
Couchbase is a NoSQL document database designed for high-performance applications. It offers a unique combination of scalability, flexibility, and powerful querying capabilities, making it ideal for modern web and mobile applications.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key Features}
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Distributed Architecture: Ensures high availability and scalability.&lt;/li&gt;
&lt;li&gt;N1QL Query Language: SQL-like query language for JSON data.&lt;/li&gt;
&lt;li&gt;Real-time Sync: Synchronize data across devices with Couchbase Mobile.&lt;/li&gt;
&lt;li&gt;Flexible Data Model: Store data in JSON format.&lt;/li&gt;
&lt;li&gt;Offline Support: Built-in support for offline-first applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up Couchbase for Your App
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Step 1: Install Couchbase Server
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Download Couchbase Server from the official website.&lt;/li&gt;
&lt;li&gt;Follow the installation instructions for your operating system.&lt;/li&gt;
&lt;li&gt;Start the Couchbase Server and access the web console at &lt;a href="http://localhost:8091" rel="noopener noreferrer"&gt;http://localhost:8091&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 2: Create a Bucket
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Log in to the Couchbase web console.&lt;/li&gt;
&lt;li&gt;Navigate to the Buckets section and create a new bucket for your application data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 3: Set Up Couchbase SDK
&lt;/h2&gt;

&lt;p&gt;Install the Couchbase SDK for your platform. For example, in a Node.js application:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install couchbase&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Initialize Couchbase in your app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const couchbase = require('couchbase');

const cluster = new couchbase.Cluster('couchbase://127.0.0.1', {
  username: 'Administrator',
  password: 'password',
});
const bucket = cluster.bucket('your-bucket-name');
const collection = bucket.defaultCollection();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Define Your Data Model
&lt;/h2&gt;

&lt;p&gt;Couchbase uses a document model to store data. Here’s an example structure for a task management app:&lt;/p&gt;

&lt;h1&gt;
  
  
  Tasks (Bucket)
&lt;/h1&gt;

&lt;p&gt;Document 1&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;id: "1"&lt;/li&gt;
&lt;li&gt;title: "Build Couchbase App"&lt;/li&gt;
&lt;li&gt;description: "Learn how to integrate Couchbase."&lt;/li&gt;
&lt;li&gt;&lt;p&gt;status: "In Progress"&lt;br&gt;
Document 2&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;id: "2"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;title: "Publish Article"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;description: "Publish on Dev.to."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;status: "Pending"&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 5: CRUD Operations
&lt;/h2&gt;

&lt;p&gt;Add Data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const addTask = async (task) =&amp;gt; {
  try {
    await collection.insert(task.id, task);
    console.log("Task added successfully.");
  } catch (err) {
    console.error("Error adding task: ", err);
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read Data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const fetchTasks = async () =&amp;gt; {
  try {
    const query = "SELECT * FROM `your-bucket-name`";
    const result = await cluster.query(query);
    result.rows.forEach((row) =&amp;gt; {
      console.log(row);
    });
  } catch (err) {
    console.error("Error fetching tasks: ", err);
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update Data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const updateTask = async (taskId, updatedFields) =&amp;gt; {
  try {
    await collection.mutateIn(taskId, [
      couchbase.MutateInSpec.upsert("status", updatedFields.status),
    ]);
    console.log("Task updated successfully.");
  } catch (err) {
    console.error("Error updating task: ", err);
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Delete Data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const deleteTask = async (taskId) =&amp;gt; {
  try {
    await collection.remove(taskId);
    console.log("Task deleted successfully.");
  } catch (err) {
    console.error("Error deleting task: ", err);
  }
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Once your application is ready, deploy it to your chosen platform. Couchbase integrates well with cloud platforms like AWS, Azure, and Google Cloud. You can also use Docker to containerize your application:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker run -d --name couchbase -p 8091-8096:8091-8096 -p 11210:11210 couchbase&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Using a cloud NoSQL database like Couchbase can streamline app development by providing high performance, scalability, and ease of use. By following the steps outlined in this article, you can build robust applications that leverage the power of modern NoSQL databases.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Construyendo una aplicación con Change Data Capture (CDC) utilizando Debezium, Kafka y NiFi</title>
      <dc:creator>Javier Andre Neira Machaca</dc:creator>
      <pubDate>Sat, 14 Dec 2024 17:08:18 +0000</pubDate>
      <link>https://dev.to/draylexter/construyendo-una-aplicacion-con-change-data-capture-cdc-utilizando-debezium-kafka-y-nifi-ei</link>
      <guid>https://dev.to/draylexter/construyendo-una-aplicacion-con-change-data-capture-cdc-utilizando-debezium-kafka-y-nifi-ei</guid>
      <description>&lt;p&gt;En este artículo aprenderás a crear una aplicación con capacidades de &lt;strong&gt;Change Data Capture (CDC)&lt;/strong&gt; utilizando &lt;strong&gt;Debezium&lt;/strong&gt;, &lt;strong&gt;Apache Kafka&lt;/strong&gt; y &lt;strong&gt;Apache NiFi&lt;/strong&gt;. Este enfoque te permitirá capturar, procesar y transmitir cambios en tus datos en tiempo real, habilitando flujos de datos modernos y reactivos. Al final del artículo encontrarás un enlace a un repositorio de GitHub con código de ejemplo para que puedas replicar el entorno en tu máquina.&lt;/p&gt;




&lt;h2&gt;
  
  
  ¿Qué es el Change Data Capture (CDC)?
&lt;/h2&gt;

&lt;p&gt;El &lt;strong&gt;Change Data Capture (CDC)&lt;/strong&gt; es un patrón que permite capturar las mutaciones de datos (inserciones, actualizaciones y eliminaciones) ocurridas en un sistema de origen. En lugar de depender de lecturas periódicas (batch) que pueden ser costosas e ineficientes, el CDC detecta y emite eventos tan pronto como se producen, lo que facilita la replicación, sincronización y análisis en tiempo real.&lt;/p&gt;

&lt;p&gt;Algunas ventajas del CDC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sincronización de datos en tiempo real&lt;/strong&gt;: Mantener múltiples sistemas alineados sin importar la frecuencia de cambios.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Análisis en vivo&lt;/strong&gt;: Procesar datos en el momento exacto en que ocurren los eventos, ideal para dashboards, alertas o análisis inmediato.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Menor latencia&lt;/strong&gt;: Comparado con procesos ETL tradicionales, se evitan los “batch windows”.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalabilidad y resiliencia&lt;/strong&gt;: Integrado con sistemas de mensajería distribuida como Kafka, se logra un pipeline flexible y escalable.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Herramientas Clave en la Arquitectura
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debezium&lt;/strong&gt;: Una plataforma de CDC que se integra con distintos motores de base de datos (MySQL, PostgreSQL, Oracle, MongoDB, etc.). Debezium captura los cambios a nivel de binlog (o equivalente) y los convierte en eventos, que luego publica en Kafka.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apache Kafka&lt;/strong&gt;: Un sistema de mensajería distribuido, escalable y altamente disponible. Sirve como capa intermedia para almacenar y transmitir los eventos generados por Debezium. Los consumidores pueden leer estos eventos en tiempo real.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apache NiFi&lt;/strong&gt;: Una herramienta de integración y automatización de flujos de datos basada en una interfaz gráfica (low-code), que facilita la transformación, enrutamiento y distribución de datos hacia sistemas destino (bases de datos analíticas, data lakes, almacenamiento en la nube, etc.).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Arquitectura General del Pipeline
&lt;/h2&gt;

&lt;p&gt;La arquitectura típica consta de:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base de Datos Origen&lt;/strong&gt;: Donde se ejecutan transacciones. Por ejemplo, una base MySQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Debezium&lt;/strong&gt;: Detecta cambios y produce eventos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kafka&lt;/strong&gt;: Recibe eventos desde Debezium y los pone a disposición de cualquier consumidor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NiFi u otras Aplicaciones&lt;/strong&gt;: Consumen, transforman y reenvían estos datos a sistemas de destino (por ejemplo, ElasticSearch, HDFS, otra base de datos).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Servicios Destino&lt;/strong&gt;: Donde se utilizan los datos (reportes, dashboards, aplicaciones web, análisis en tiempo real).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pasos para Implementar el Pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Configurar la Base de Datos de Origen
&lt;/h3&gt;

&lt;p&gt;Asume que usas &lt;strong&gt;MySQL&lt;/strong&gt;. Asegúrate de habilitar el binlog y el formato de registro adecuado (ROW):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[mysqld]&lt;/span&gt;
&lt;span class="py"&gt;log_bin&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;mysql-bin&lt;/span&gt;
&lt;span class="py"&gt;binlog_format&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ROW&lt;/span&gt;
&lt;span class="py"&gt;server_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crea un usuario con permisos para que Debezium pueda leer el binlog.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Levantar Kafka y Debezium con Docker
&lt;/h3&gt;

&lt;p&gt;Crea un archivo docker-compose.yml similar a:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:7.0.1
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
    ports:
      - "2181:2181"

  kafka:
    image: confluentinc/cp-kafka:7.0.1
    depends_on:
      - zookeeper
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
    ports:
      - "9092:9092"

  debezium:
    image: debezium/connect:1.9
    ports:
      - "8083:8083"
    environment:
      BOOTSTRAP_SERVERS: kafka:9092
      GROUP_ID: 1
      CONFIG_STORAGE_TOPIC: debezium_config
      OFFSET_STORAGE_TOPIC: debezium_offset
      STATUS_STORAGE_TOPIC: debezium_status
    depends_on:
      - kafka
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Configurar el Conector Debezium
&lt;/h3&gt;

&lt;p&gt;Con Debezium en marcha, registra un conector que apunte a tu base de datos MySQL. Por ejemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -i -X POST -H "Accept:application/json" -H "Content-Type:application/json" \
  localhost:8083/connectors/ -d '{
    "name": "mysql-connector",
    "config": {
      "connector.class": "io.debezium.connector.mysql.MySqlConnector",
      "tasks.max": "1",
      "database.hostname": "tu_mysql_host",
      "database.port": "3306",
      "database.user": "debezium",
      "database.password": "debeziumpwd",
      "database.server.id": "184054",
      "database.server.name": "fullfillment_app",
      "database.include.list": "mydb",
      "database.history.kafka.bootstrap.servers": "kafka:9092",
      "database.history.kafka.topic": "schema-changes.mydb"
    }
  }'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Consumir Eventos con Apache NiFi
&lt;/h3&gt;

&lt;p&gt;En NiFi, utiliza un ConsumeKafkaRecord_2_x para leer eventos de un tópico específico. Luego, con procesadores como JoltTransformJSON puedes transformar el payload. Finalmente, envía los datos con PutDatabaseRecord a otra base de datos, o PutElasticsearchHttpRecord a un índice Elasticsearch.&lt;/p&gt;

&lt;p&gt;El flujo podría ser:&lt;br&gt;
&lt;code&gt;[ConsumeKafkaRecord_2_x] -&amp;gt; [JoltTransformJSON] -&amp;gt; [PutDatabaseRecord]&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Adapta los procesadores según tus necesidades y ajusta las propiedades (tópico Kafka, host de destino, etc.).&lt;/p&gt;

</description>
      <category>cdc</category>
      <category>bigdata</category>
    </item>
    <item>
      <title>Creating a To-Do List App with Firebase Firestore</title>
      <dc:creator>Javier Andre Neira Machaca</dc:creator>
      <pubDate>Thu, 14 Nov 2024 05:18:27 +0000</pubDate>
      <link>https://dev.to/draylexter/creating-a-to-do-list-app-with-firebase-firestore-1605</link>
      <guid>https://dev.to/draylexter/creating-a-to-do-list-app-with-firebase-firestore-1605</guid>
      <description>&lt;p&gt;In this post, I will show you how to create a to-do list application using HTML, CSS, JavaScript, and Firebase Firestore. This guide will help you understand how to integrate a cloud database with a simple web application, providing a complete experience from setup to implementation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technologies We Will Use:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML/CSS: For the structure and design of the application, ensuring that the interface is intuitive and easy to use.&lt;/li&gt;
&lt;li&gt;JavaScript: For the application logic, adding interactivity and communicating with Firebase. This includes manipulating the DOM, handling events, and performing CRUD (Create, Read, Update, Delete) operations.&lt;/li&gt;
&lt;li&gt;Firebase Firestore: As our cloud database to store tasks. Firestore allows us to store structured data and access it in real time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Project Structure&lt;/strong&gt;&lt;br&gt;
Our project has the following file structure:&lt;br&gt;
&lt;code&gt;&lt;br&gt;
firebase-todo-app/&lt;br&gt;
|&lt;br&gt;
├── src/&lt;br&gt;
│   ├── css/&lt;br&gt;
│   │   └── styles.css&lt;br&gt;
│   └── js/&lt;br&gt;
│       └── app.js&lt;br&gt;
│&lt;br&gt;
├── index.html&lt;br&gt;
└── README.md&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;index.html is the main file that loads in the browser and contains the base structure of the application.&lt;/li&gt;
&lt;li&gt;styles.css contains the styles that make our application look good and visually appealing.&lt;/li&gt;
&lt;li&gt;app.js is where all the JavaScript logic for handling tasks resides, including integration with Firebase Firestore.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Firebase Setup&lt;/strong&gt;&lt;br&gt;
Before starting with the code, you need to configure Firebase. You can create a new project from Firebase Console, enable Firestore Database, and copy the project configuration.&lt;/p&gt;

&lt;p&gt;Then, in the app.js file, add the Firebase configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const firebaseConfig = {
    apiKey: "YOUR_API_KEY",
    authDomain: "YOUR_AUTH_DOMAIN",
    projectId: "YOUR_PROJECT_ID",
    storageBucket: "YOUR_STORAGE_BUCKET",
    messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
    appId: "YOUR_APP_ID"
};

firebase.initializeApp(firebaseConfig);
const db = firebase.firestore();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we have connected our application to Firebase Firestore.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Creating the User Interface&lt;/strong&gt;&lt;br&gt;
In our index.html file, we have a simple structure that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A title &lt;code&gt;(&amp;lt;h1&amp;gt;)&lt;/code&gt; for the application.&lt;/li&gt;
&lt;li&gt;A dropdown () to filter tasks (all, completed, pending).&lt;/li&gt;
&lt;li&gt;A container () to display our tasks.
&lt;/li&gt;
&lt;li&gt;An input field () and a button () to add new tasks.&lt;/li&gt;
&lt;li&gt;A container for messages () where we will display status messages for the user.


&lt;p&gt;Here is the HTML code:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Firebase To-Do App&amp;lt;/title&amp;gt;
    &amp;lt;link rel="stylesheet" href="css/styles.css"&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Firebase To-Do List&amp;lt;/h1&amp;gt;
    &amp;lt;select id="filter"&amp;gt;
        &amp;lt;option value="all"&amp;gt;All&amp;lt;/option&amp;gt;
        &amp;lt;option value="completed"&amp;gt;Completed&amp;lt;/option&amp;gt;
        &amp;lt;option value="pending"&amp;gt;Pending&amp;lt;/option&amp;gt;
    &amp;lt;/select&amp;gt;
    &amp;lt;div id="todo-container"&amp;gt;
        &amp;lt;p&amp;gt;Loading tasks...&amp;lt;/p&amp;gt; &amp;lt;!-- Initial loading message --&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;input type="text" id="todo-input" placeholder="New task..."&amp;gt;
    &amp;lt;button id="add-button"&amp;gt;Add Task&amp;lt;/button&amp;gt;
    &amp;lt;!-- Container for messages --&amp;gt;
    &amp;lt;div id="message"&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;!-- Load Firebase from CDN (compat version) --&amp;gt;
    &amp;lt;script src="https://www.gstatic.com/firebasejs/9.6.1/firebase-app-compat.js"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src="https://www.gstatic.com/firebasejs/9.6.1/firebase-firestore-compat.js"&amp;gt;&amp;lt;/script&amp;gt;

    &amp;lt;!-- Your JavaScript file --&amp;gt;
    &amp;lt;script src="js/app.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Styling with CSS&lt;/strong&gt;&lt;br&gt;
The styles.css file allows us to give a pleasant visual style to the application. Here are some of the styles we applied:&lt;/p&gt;

&lt;p&gt;General Design: We use a sans-serif font to give the application a modern and clean look.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task Container: The container (#todo-container) has rounded borders, shadow, and a white background to stand out against the general background. This helps keep tasks organized and well defined.&lt;/li&gt;
&lt;li&gt;Buttons: The "Add Task" button has a green background that changes when hovered over to indicate that it is active and to invite the user to interact with it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 4: JavaScript Logic&lt;/strong&gt;&lt;br&gt;
In the app.js file, we define the logic for adding, displaying, editing, and deleting tasks. Firebase allows us to store tasks in the database and listen for changes in real time.&lt;/p&gt;

&lt;p&gt;Adding a Task&lt;/p&gt;

&lt;p&gt;To add a new task, we use the addTodo() function that takes the value from the input field and saves it in Firestore. Additionally, we ask the user if they want to add an optional due date:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function addTodo() {
    const todoInput = document.getElementById("todo-input").value;
    const dueDateInput = prompt("Due date (optional): YYYY-MM-DD");
    const messageDiv = document.getElementById("message");

    if (todoInput) {
        try {
            const createdAt = new Date();
            const dueDate = dueDateInput ? new Date(dueDateInput) : null;

            await db.collection("todos").add({ text: todoInput, completed: false, createdAt, dueDate });
            document.getElementById("todo-input").value = "";
            showMessage("Task added successfully!", "green");
        } catch (error) {
            showMessage("Error adding task: " + error.message, "red");
        }
    } else {
        showMessage("Please enter a task.", "red");
    }
}
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;In this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We validate that the input field is not empty.&lt;/li&gt;
&lt;li&gt;We create an object with the creation date and optionally a due date.&lt;/li&gt;
&lt;li&gt;We use db.collection("todos").add() to save the task in Firestore.&lt;/li&gt;
&lt;li&gt;We display a success or error message using the showMessage() function.&lt;/li&gt;
&lt;li&gt;Displaying Tasks in Real Time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The loadTodos() function listens for changes in the database using onSnapshot() and displays all tasks in the interface. This function also allows filtering tasks by their status:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function loadTodos(filter = "all") {
    let query = db.collection("todos");

    if (filter === "completed") {
        query = query.where("completed", "==", true);
    } else if (filter === "pending") {
        query = query.where("completed", "==", false);
    }

    query.onSnapshot((snapshot) =&amp;gt; {
        const todoContainer = document.getElementById("todo-container");
        todoContainer.innerHTML = "";
        snapshot.forEach((doc) =&amp;gt; {
            const taskData = doc.data();
            const taskId = doc.id;

            const task = document.createElement("div");
            task.textContent = taskData.text;

            // Display creation and due dates
            if (taskData.createdAt) {
                const createdDate = new Date(taskData.createdAt.seconds * 1000);
                task.textContent += ` (Created: ${createdDate.toLocaleDateString()})`;
            }

            if (taskData.dueDate) {
                const dueDate = new Date(taskData.dueDate.seconds * 1000);
                task.textContent += ` (Due: ${dueDate.toLocaleDateString()})`;
            }

            if (taskData.completed) {
                task.style.textDecoration = "line-through";
                task.style.color = "gray";
            }

            const completeButton = document.createElement("button");
            completeButton.textContent = "✔️";
            completeButton.style.marginLeft = "10px";
            completeButton.onclick = () =&amp;gt; markAsCompleted(taskId);

            const editButton = document.createElement("button");
            editButton.textContent = "✏️";
            editButton.style.marginLeft = "5px";
            editButton.onclick = () =&amp;gt; editTask(taskId, taskData.text);

            const deleteButton = document.createElement("button");
            deleteButton.textContent = "🗑️";
            deleteButton.style.marginLeft = "5px";
            deleteButton.onclick = () =&amp;gt; deleteTask(taskId);

            task.appendChild(completeButton);
            task.appendChild(editButton);
            task.appendChild(deleteButton);
            todoContainer.appendChild(task);
        });
    });
}
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;In this code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We filter tasks by status (completed, pending, or all).&lt;/li&gt;
&lt;li&gt;We listen for changes in real time with onSnapshot() to keep the interface automatically updated.&lt;/li&gt;
&lt;li&gt;We dynamically create HTML elements to display each task, along with buttons to complete, edit, and delete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
Creating a to-do list application with Firebase is an excellent way to learn how to work with cloud databases and understand how to build a complete application with HTML, CSS, and JavaScript. Throughout this project, we explored how to add, edit, delete, and display tasks using Firestore, which provides real-time synchronization so users always have updated data.&lt;br&gt;
Firebase makes it easy to implement many of the features needed for modern applications, such as cloud data persistence and real-time updates. With the right structure and development best practices, this project can be extended to add more advanced features like user authentication, notifications, or file storage.&lt;br&gt;
I hope this guide helps you learn and develop your own applications with Firebase. If you have any questions or suggestions, feel free to leave a comment!&lt;br&gt;
&lt;a href="https://github.com/Dray-Lexter/firebase-todo-app.git" rel="noopener noreferrer"&gt;https://github.com/Dray-Lexter/firebase-todo-app.git&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;


&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
