From a445b7fe74f091f551cd04dfdf47f68f79c07ef2 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 14:42:35 -0300 Subject: [PATCH 01/25] Delete .github/ISSUE_TEMPLATE directory chore: remove upstream issue templates to enable portfolio workflow --- .github/ISSUE_TEMPLATE/config.yml | 10 ---------- .github/ISSUE_TEMPLATE/privileged.yml | 22 ---------------------- 2 files changed, 32 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/config.yml delete mode 100644 .github/ISSUE_TEMPLATE/privileged.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 50bde36072..0000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,10 +0,0 @@ -blank_issues_enabled: false -contact_links: - - name: Security Contact - about: Please report security vulnerabilities to security@tiangolo.com - - name: Question or Problem - about: Ask a question or ask about a problem in GitHub Discussions. - url: https://github.com/fastapi/full-stack-fastapi-template/discussions/categories/questions - - name: Feature Request - about: To suggest an idea or ask about a feature, please start with a question saying what you would like to achieve. There might be a way to do it already. - url: https://github.com/fastapi/full-stack-fastapi-template/discussions/categories/questions diff --git a/.github/ISSUE_TEMPLATE/privileged.yml b/.github/ISSUE_TEMPLATE/privileged.yml deleted file mode 100644 index 6438848c83..0000000000 --- a/.github/ISSUE_TEMPLATE/privileged.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: Privileged -description: You are @tiangolo or he asked you directly to create an issue here. If not, check the other options. 👇 -body: - - type: markdown - attributes: - value: | - Thanks for your interest in this project! 🚀 - - If you are not @tiangolo or he didn't ask you directly to create an issue here, please start the conversation in a [Question in GitHub Discussions](https://github.com/tiangolo/full-stack-fastapi-template/discussions/categories/questions) instead. - - type: checkboxes - id: privileged - attributes: - label: Privileged issue - description: Confirm that you are allowed to create an issue here. - options: - - label: I'm @tiangolo or he asked me directly to create an issue here. - required: true - - type: textarea - id: content - attributes: - label: Issue Content - description: Add the content of the issue here. From 5405d4806b4f870f461093a3d71480fa8d263356 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:41:05 -0300 Subject: [PATCH 02/25] Create arquitectura.md for DevOps portfolio Added initial architecture documentation for DevOps portfolio. --- docs/arquitectura.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 docs/arquitectura.md diff --git a/docs/arquitectura.md b/docs/arquitectura.md new file mode 100644 index 0000000000..10f5335409 --- /dev/null +++ b/docs/arquitectura.md @@ -0,0 +1,10 @@ +# Arquitectura (Portfolio DevOps) + +Este repositorio se utiliza como portfolio profesional DevOps/Cloud. + +Objetivo del proyecto: +- Flujo local con Docker (reproducible) +- Flujo local con Kubernetes (kind) +- CI/CD con GitHub Actions +- Deploy automático al hacer merge a main hacia AWS (EC2 + k3s, sin EKS) + From 02fa41c99a2072263e8f825c43bed1fa847896e8 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:41:59 -0300 Subject: [PATCH 03/25] Agregamos decisiones.md Document technical decisions regarding the project infrastructure, deployment, and CI/CD practices. --- docs/decisiones.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/decisiones.md diff --git a/docs/decisiones.md b/docs/decisiones.md new file mode 100644 index 0000000000..cb8288d849 --- /dev/null +++ b/docs/decisiones.md @@ -0,0 +1,14 @@ +# Decisiones técnicas + +## 0001 - App base: template open-source (código secundario) +Se utiliza una aplicación open-source existente como base. + +**El foco del repositorio es la infraestructura, automatización y despliegue (prácticas DevOps).** + +## 0002 - Kubernetes: kind en local, k3s en AWS EC2 (sin EKS) +Se eligen alternativas livianas para mantener el alcance terminable y ejecutable, evitando complejidad innecesaria. + +## 0003 - CI/CD con GitHub Actions +Se utiliza GitHub Actions para: +- CI en Pull Requests (checks de calidad) +- CD al mergear a main (deploy automático) From c2e990b19656016acf9df88e2b2ee08f095ec91c Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:42:42 -0300 Subject: [PATCH 04/25] Add README for Kubernetes portfolio manifests --- k8s/portfolio/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 k8s/portfolio/README.md diff --git a/k8s/portfolio/README.md b/k8s/portfolio/README.md new file mode 100644 index 0000000000..36044ba5cd --- /dev/null +++ b/k8s/portfolio/README.md @@ -0,0 +1,8 @@ +# Manifiestos Kubernetes (portfolio) + +En esta carpeta van a vivir los manifiestos Kubernetes creados como parte del portfolio. + +Principios: +- Separar el “trabajo propio” del contenido upstream del template +- Mantenerlo incremental por fases +- Minimizar complejidad: primero kind (local), luego k3s (AWS) From 34b8a7076bd1853f3cde76aab4e1531def5ce8a3 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:43:34 -0300 Subject: [PATCH 05/25] Create README for GitHub workflows Added README for workflows explaining CI and CD. --- .github/workflows/README.MD | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/workflows/README.MD diff --git a/.github/workflows/README.MD b/.github/workflows/README.MD new file mode 100644 index 0000000000..65569ccd35 --- /dev/null +++ b/.github/workflows/README.MD @@ -0,0 +1,7 @@ +# Workflows (portfolio) + +Workflows del portfolio: +- ci.yml: se ejecuta en Pull Requests +- cd.yml: deploy automático al mergear a main + +Se construyen de forma incremental. From 2a3a6fc34a8056527de8ebb9b0daad520e4c4019 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:53:49 -0300 Subject: [PATCH 06/25] Actualizamos README para portfolio DevOps Updated project title and description to reflect DevOps focus and modern practices. Added sections in Spanish about architecture, usage, and skills demonstrated. --- README.md | 277 +++++++++--------------------------------------------- 1 file changed, 44 insertions(+), 233 deletions(-) diff --git a/README.md b/README.md index a9049b4779..c25f5b52ef 100644 --- a/README.md +++ b/README.md @@ -1,233 +1,44 @@ -# Full Stack FastAPI Template - -Test Docker Compose -Test Backend -Coverage - -## Technology Stack and Features - -- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API. - - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM). - - 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management. - - 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database. -- 🚀 [React](https://react.dev) for the frontend. - - 💃 Using TypeScript, hooks, [Vite](https://vitejs.dev), and other parts of a modern frontend stack. - - 🎨 [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for the frontend components. - - 🤖 An automatically generated frontend client. - - 🧪 [Playwright](https://playwright.dev) for End-to-End testing. - - 🦇 Dark mode support. -- 🐋 [Docker Compose](https://www.docker.com) for development and production. -- 🔒 Secure password hashing by default. -- 🔑 JWT (JSON Web Token) authentication. -- 📫 Email based password recovery. -- 📬 [Mailcatcher](https://mailcatcher.me) for local email testing during development. -- ✅ Tests with [Pytest](https://pytest.org). -- 📞 [Traefik](https://traefik.io) as a reverse proxy / load balancer. -- 🚢 Deployment instructions using Docker Compose, including how to set up a frontend Traefik proxy to handle automatic HTTPS certificates. -- 🏭 CI (continuous integration) and CD (continuous deployment) based on GitHub Actions. - -### Dashboard Login - -[![API docs](img/login.png)](https://github.com/fastapi/full-stack-fastapi-template) - -### Dashboard - Admin - -[![API docs](img/dashboard.png)](https://github.com/fastapi/full-stack-fastapi-template) - -### Dashboard - Items - -[![API docs](img/dashboard-items.png)](https://github.com/fastapi/full-stack-fastapi-template) - -### Dashboard - Dark Mode - -[![API docs](img/dashboard-dark.png)](https://github.com/fastapi/full-stack-fastapi-template) - -### Interactive API Documentation - -[![API docs](img/docs.png)](https://github.com/fastapi/full-stack-fastapi-template) - -## How To Use It - -You can **just fork or clone** this repository and use it as is. - -✨ It just works. ✨ - -### How to Use a Private Repository - -If you want to have a private repository, GitHub won't allow you to simply fork it as it doesn't allow changing the visibility of forks. - -But you can do the following: - -- Create a new GitHub repo, for example `my-full-stack`. -- Clone this repository manually, set the name with the name of the project you want to use, for example `my-full-stack`: - -```bash -git clone git@github.com:fastapi/full-stack-fastapi-template.git my-full-stack -``` - -- Enter into the new directory: - -```bash -cd my-full-stack -``` - -- Set the new origin to your new repository, copy it from the GitHub interface, for example: - -```bash -git remote set-url origin git@github.com:octocat/my-full-stack.git -``` - -- Add this repo as another "remote" to allow you to get updates later: - -```bash -git remote add upstream git@github.com:fastapi/full-stack-fastapi-template.git -``` - -- Push the code to your new repository: - -```bash -git push -u origin master -``` - -### Update From the Original Template - -After cloning the repository, and after doing changes, you might want to get the latest changes from this original template. - -- Make sure you added the original repository as a remote, you can check it with: - -```bash -git remote -v - -origin git@github.com:octocat/my-full-stack.git (fetch) -origin git@github.com:octocat/my-full-stack.git (push) -upstream git@github.com:fastapi/full-stack-fastapi-template.git (fetch) -upstream git@github.com:fastapi/full-stack-fastapi-template.git (push) -``` - -- Pull the latest changes without merging: - -```bash -git pull --no-commit upstream master -``` - -This will download the latest changes from this template without committing them, that way you can check everything is right before committing. - -- If there are conflicts, solve them in your editor. - -- Once you are done, commit the changes: - -```bash -git merge --continue -``` - -### Configure - -You can then update configs in the `.env` files to customize your configurations. - -Before deploying it, make sure you change at least the values for: - -- `SECRET_KEY` -- `FIRST_SUPERUSER_PASSWORD` -- `POSTGRES_PASSWORD` - -You can (and should) pass these as environment variables from secrets. - -Read the [deployment.md](./deployment.md) docs for more details. - -### Generate Secret Keys - -Some environment variables in the `.env` file have a default value of `changethis`. - -You have to change them with a secret key, to generate secret keys you can run the following command: - -```bash -python -c "import secrets; print(secrets.token_urlsafe(32))" -``` - -Copy the content and use that as password / secret key. And run that again to generate another secure key. - -## How To Use It - Alternative With Copier - -This repository also supports generating a new project using [Copier](https://copier.readthedocs.io). - -It will copy all the files, ask you configuration questions, and update the `.env` files with your answers. - -### Install Copier - -You can install Copier with: - -```bash -pip install copier -``` - -Or better, if you have [`pipx`](https://pipx.pypa.io/), you can run it with: - -```bash -pipx install copier -``` - -**Note**: If you have `pipx`, installing copier is optional, you could run it directly. - -### Generate a Project With Copier - -Decide a name for your new project's directory, you will use it below. For example, `my-awesome-project`. - -Go to the directory that will be the parent of your project, and run the command with your project's name: - -```bash -copier copy https://github.com/fastapi/full-stack-fastapi-template my-awesome-project --trust -``` - -If you have `pipx` and you didn't install `copier`, you can run it directly: - -```bash -pipx run copier copy https://github.com/fastapi/full-stack-fastapi-template my-awesome-project --trust -``` - -**Note** the `--trust` option is necessary to be able to execute a [post-creation script](https://github.com/fastapi/full-stack-fastapi-template/blob/master/.copier/update_dotenv.py) that updates your `.env` files. - -### Input Variables - -Copier will ask you for some data, you might want to have at hand before generating the project. - -But don't worry, you can just update any of that in the `.env` files afterwards. - -The input variables, with their default values (some auto generated) are: - -- `project_name`: (default: `"FastAPI Project"`) The name of the project, shown to API users (in .env). -- `stack_name`: (default: `"fastapi-project"`) The name of the stack used for Docker Compose labels and project name (no spaces, no periods) (in .env). -- `secret_key`: (default: `"changethis"`) The secret key for the project, used for security, stored in .env, you can generate one with the method above. -- `first_superuser`: (default: `"admin@example.com"`) The email of the first superuser (in .env). -- `first_superuser_password`: (default: `"changethis"`) The password of the first superuser (in .env). -- `smtp_host`: (default: "") The SMTP server host to send emails, you can set it later in .env. -- `smtp_user`: (default: "") The SMTP server user to send emails, you can set it later in .env. -- `smtp_password`: (default: "") The SMTP server password to send emails, you can set it later in .env. -- `emails_from_email`: (default: `"info@example.com"`) The email account to send emails from, you can set it later in .env. -- `postgres_password`: (default: `"changethis"`) The password for the PostgreSQL database, stored in .env, you can generate one with the method above. -- `sentry_dsn`: (default: "") The DSN for Sentry, if you are using it, you can set it later in .env. - -## Backend Development - -Backend docs: [backend/README.md](./backend/README.md). - -## Frontend Development - -Frontend docs: [frontend/README.md](./frontend/README.md). - -## Deployment - -Deployment docs: [deployment.md](./deployment.md). - -## Development - -General development docs: [development.md](./development.md). - -This includes using Docker Compose, custom local domains, `.env` configurations, etc. - -## Release Notes - -Check the file [release-notes.md](./release-notes.md). - -## License - -The Full Stack FastAPI Template is licensed under the terms of the MIT license. +# DevOps Portfolio — FastAPI Template (Docker + Kubernetes + CI/CD + AWS) + +Este repositorio es un **portfolio personal DevOps/Cloud**. El objetivo es demostrar prácticas modernas de: +- Docker +- Kubernetes (kind en local / k3s en AWS EC2 — **sin EKS**) +- CI/CD con GitHub Actions +- Deploy automático al mergear Pull Requests + +> La aplicación se utiliza como base open-source. El foco principal es infraestructura, automatización y despliegue. + +## Qué vas a encontrar acá +- `docs/`: arquitectura, decisiones técnicas y guías de ejecución +- `k8s/portfolio/`: manifiestos Kubernetes creados como parte del portfolio +- `.github/workflows/`: pipelines del portfolio (CI y CD) + +## Arquitectura (resumen) +- **Local (Docker):** ejecución reproducible con Docker/Compose +- **Local (Kubernetes):** cluster kind + manifests del portfolio +- **AWS:** instancia EC2 corriendo k3s + Nginx Ingress Controller +- **CI/CD:** GitHub Actions: + - CI en Pull Requests + - CD al mergear a `main` + +## Cómo ejecutarlo +- Local con Docker: ver `docs/runbooks/local-docker.md` +- Kubernetes local (kind): ver `docs/runbooks/kind.md` +- AWS (EC2 + k3s): ver `docs/runbooks/aws-k3s.md` + +## Skills DevOps demostradas +- Containerización y buenas prácticas Docker +- Deploy y troubleshooting en Kubernetes +- Automatización CI/CD con GitHub Actions +- Deploy automático a infraestructura en AWS (sin EKS) +- Documentación técnica orientada a entrevistas + +## Roadmap +- [ ] Phase 1: Docker baseline +- [ ] Phase 2: Kubernetes local (kind) +- [ ] Phase 3: CI/CD +- [ ] Phase 4: AWS EC2 + k3s deploy + +--- + +📌 Autor: AlfreMu From 512659a67f76cae90554b4ca98888490bd287316 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:54:18 -0300 Subject: [PATCH 07/25] Add runbook for local Docker setup --- docs/runbooks/local-docker.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/runbooks/local-docker.md diff --git a/docs/runbooks/local-docker.md b/docs/runbooks/local-docker.md new file mode 100644 index 0000000000..68acd4d242 --- /dev/null +++ b/docs/runbooks/local-docker.md @@ -0,0 +1,5 @@ +# Runbook — Local (Docker) + +> Pendiente: se completará en Phase 1 (Docker baseline). + +Objetivo: levantar el stack localmente con Docker/Compose de forma reproducible. From f2bd91c19f829711198fb6603369bcdc32182f4c Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:54:32 -0300 Subject: [PATCH 08/25] Create kind.md --- docs/runbooks/kind.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/runbooks/kind.md diff --git a/docs/runbooks/kind.md b/docs/runbooks/kind.md new file mode 100644 index 0000000000..86f455c300 --- /dev/null +++ b/docs/runbooks/kind.md @@ -0,0 +1,5 @@ +# Runbook — Kubernetes local (kind) + +> Pendiente: se completará en Phase 2 (Kubernetes local). + +Objetivo: levantar el stack en un cluster kind y acceder vía Ingress. From e3e45a538da28e057d65093a5dd5a7871bdfb88a Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:54:48 -0300 Subject: [PATCH 09/25] Create aws-k3s.md --- docs/runbooks/aws-k3s.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/runbooks/aws-k3s.md diff --git a/docs/runbooks/aws-k3s.md b/docs/runbooks/aws-k3s.md new file mode 100644 index 0000000000..7eab1cd14e --- /dev/null +++ b/docs/runbooks/aws-k3s.md @@ -0,0 +1,5 @@ +# Runbook — AWS (EC2 + k3s) + +> Pendiente: se completará en Phase 4 (AWS deploy). + +Objetivo: desplegar automáticamente al mergear a main hacia un cluster k3s corriendo en EC2. From 8704e0a164253541f61d0d142d2fc57088aeac86 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:55:47 -0300 Subject: [PATCH 10/25] Create upstream --- docs/upstream | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/upstream diff --git a/docs/upstream b/docs/upstream new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/docs/upstream @@ -0,0 +1 @@ + From ec8284bdaf06e805281ad18fa04a51fdcbeda122 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:56:05 -0300 Subject: [PATCH 11/25] Delete docs/upstream --- docs/upstream | 1 - 1 file changed, 1 deletion(-) delete mode 100644 docs/upstream diff --git a/docs/upstream b/docs/upstream deleted file mode 100644 index 8b13789179..0000000000 --- a/docs/upstream +++ /dev/null @@ -1 +0,0 @@ - From 6c235d05dd89a693329660d4a8d752c3cc145d2f Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 15:56:39 -0300 Subject: [PATCH 12/25] Create README for FastAPI template Add README for Full Stack FastAPI Template with usage instructions and technology stack details. --- docs/docstream/README-fastapi-template.md | 233 ++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 docs/docstream/README-fastapi-template.md diff --git a/docs/docstream/README-fastapi-template.md b/docs/docstream/README-fastapi-template.md new file mode 100644 index 0000000000..a9049b4779 --- /dev/null +++ b/docs/docstream/README-fastapi-template.md @@ -0,0 +1,233 @@ +# Full Stack FastAPI Template + +Test Docker Compose +Test Backend +Coverage + +## Technology Stack and Features + +- ⚡ [**FastAPI**](https://fastapi.tiangolo.com) for the Python backend API. + - 🧰 [SQLModel](https://sqlmodel.tiangolo.com) for the Python SQL database interactions (ORM). + - 🔍 [Pydantic](https://docs.pydantic.dev), used by FastAPI, for the data validation and settings management. + - 💾 [PostgreSQL](https://www.postgresql.org) as the SQL database. +- 🚀 [React](https://react.dev) for the frontend. + - 💃 Using TypeScript, hooks, [Vite](https://vitejs.dev), and other parts of a modern frontend stack. + - 🎨 [Tailwind CSS](https://tailwindcss.com) and [shadcn/ui](https://ui.shadcn.com) for the frontend components. + - 🤖 An automatically generated frontend client. + - 🧪 [Playwright](https://playwright.dev) for End-to-End testing. + - 🦇 Dark mode support. +- 🐋 [Docker Compose](https://www.docker.com) for development and production. +- 🔒 Secure password hashing by default. +- 🔑 JWT (JSON Web Token) authentication. +- 📫 Email based password recovery. +- 📬 [Mailcatcher](https://mailcatcher.me) for local email testing during development. +- ✅ Tests with [Pytest](https://pytest.org). +- 📞 [Traefik](https://traefik.io) as a reverse proxy / load balancer. +- 🚢 Deployment instructions using Docker Compose, including how to set up a frontend Traefik proxy to handle automatic HTTPS certificates. +- 🏭 CI (continuous integration) and CD (continuous deployment) based on GitHub Actions. + +### Dashboard Login + +[![API docs](img/login.png)](https://github.com/fastapi/full-stack-fastapi-template) + +### Dashboard - Admin + +[![API docs](img/dashboard.png)](https://github.com/fastapi/full-stack-fastapi-template) + +### Dashboard - Items + +[![API docs](img/dashboard-items.png)](https://github.com/fastapi/full-stack-fastapi-template) + +### Dashboard - Dark Mode + +[![API docs](img/dashboard-dark.png)](https://github.com/fastapi/full-stack-fastapi-template) + +### Interactive API Documentation + +[![API docs](img/docs.png)](https://github.com/fastapi/full-stack-fastapi-template) + +## How To Use It + +You can **just fork or clone** this repository and use it as is. + +✨ It just works. ✨ + +### How to Use a Private Repository + +If you want to have a private repository, GitHub won't allow you to simply fork it as it doesn't allow changing the visibility of forks. + +But you can do the following: + +- Create a new GitHub repo, for example `my-full-stack`. +- Clone this repository manually, set the name with the name of the project you want to use, for example `my-full-stack`: + +```bash +git clone git@github.com:fastapi/full-stack-fastapi-template.git my-full-stack +``` + +- Enter into the new directory: + +```bash +cd my-full-stack +``` + +- Set the new origin to your new repository, copy it from the GitHub interface, for example: + +```bash +git remote set-url origin git@github.com:octocat/my-full-stack.git +``` + +- Add this repo as another "remote" to allow you to get updates later: + +```bash +git remote add upstream git@github.com:fastapi/full-stack-fastapi-template.git +``` + +- Push the code to your new repository: + +```bash +git push -u origin master +``` + +### Update From the Original Template + +After cloning the repository, and after doing changes, you might want to get the latest changes from this original template. + +- Make sure you added the original repository as a remote, you can check it with: + +```bash +git remote -v + +origin git@github.com:octocat/my-full-stack.git (fetch) +origin git@github.com:octocat/my-full-stack.git (push) +upstream git@github.com:fastapi/full-stack-fastapi-template.git (fetch) +upstream git@github.com:fastapi/full-stack-fastapi-template.git (push) +``` + +- Pull the latest changes without merging: + +```bash +git pull --no-commit upstream master +``` + +This will download the latest changes from this template without committing them, that way you can check everything is right before committing. + +- If there are conflicts, solve them in your editor. + +- Once you are done, commit the changes: + +```bash +git merge --continue +``` + +### Configure + +You can then update configs in the `.env` files to customize your configurations. + +Before deploying it, make sure you change at least the values for: + +- `SECRET_KEY` +- `FIRST_SUPERUSER_PASSWORD` +- `POSTGRES_PASSWORD` + +You can (and should) pass these as environment variables from secrets. + +Read the [deployment.md](./deployment.md) docs for more details. + +### Generate Secret Keys + +Some environment variables in the `.env` file have a default value of `changethis`. + +You have to change them with a secret key, to generate secret keys you can run the following command: + +```bash +python -c "import secrets; print(secrets.token_urlsafe(32))" +``` + +Copy the content and use that as password / secret key. And run that again to generate another secure key. + +## How To Use It - Alternative With Copier + +This repository also supports generating a new project using [Copier](https://copier.readthedocs.io). + +It will copy all the files, ask you configuration questions, and update the `.env` files with your answers. + +### Install Copier + +You can install Copier with: + +```bash +pip install copier +``` + +Or better, if you have [`pipx`](https://pipx.pypa.io/), you can run it with: + +```bash +pipx install copier +``` + +**Note**: If you have `pipx`, installing copier is optional, you could run it directly. + +### Generate a Project With Copier + +Decide a name for your new project's directory, you will use it below. For example, `my-awesome-project`. + +Go to the directory that will be the parent of your project, and run the command with your project's name: + +```bash +copier copy https://github.com/fastapi/full-stack-fastapi-template my-awesome-project --trust +``` + +If you have `pipx` and you didn't install `copier`, you can run it directly: + +```bash +pipx run copier copy https://github.com/fastapi/full-stack-fastapi-template my-awesome-project --trust +``` + +**Note** the `--trust` option is necessary to be able to execute a [post-creation script](https://github.com/fastapi/full-stack-fastapi-template/blob/master/.copier/update_dotenv.py) that updates your `.env` files. + +### Input Variables + +Copier will ask you for some data, you might want to have at hand before generating the project. + +But don't worry, you can just update any of that in the `.env` files afterwards. + +The input variables, with their default values (some auto generated) are: + +- `project_name`: (default: `"FastAPI Project"`) The name of the project, shown to API users (in .env). +- `stack_name`: (default: `"fastapi-project"`) The name of the stack used for Docker Compose labels and project name (no spaces, no periods) (in .env). +- `secret_key`: (default: `"changethis"`) The secret key for the project, used for security, stored in .env, you can generate one with the method above. +- `first_superuser`: (default: `"admin@example.com"`) The email of the first superuser (in .env). +- `first_superuser_password`: (default: `"changethis"`) The password of the first superuser (in .env). +- `smtp_host`: (default: "") The SMTP server host to send emails, you can set it later in .env. +- `smtp_user`: (default: "") The SMTP server user to send emails, you can set it later in .env. +- `smtp_password`: (default: "") The SMTP server password to send emails, you can set it later in .env. +- `emails_from_email`: (default: `"info@example.com"`) The email account to send emails from, you can set it later in .env. +- `postgres_password`: (default: `"changethis"`) The password for the PostgreSQL database, stored in .env, you can generate one with the method above. +- `sentry_dsn`: (default: "") The DSN for Sentry, if you are using it, you can set it later in .env. + +## Backend Development + +Backend docs: [backend/README.md](./backend/README.md). + +## Frontend Development + +Frontend docs: [frontend/README.md](./frontend/README.md). + +## Deployment + +Deployment docs: [deployment.md](./deployment.md). + +## Development + +General development docs: [development.md](./development.md). + +This includes using Docker Compose, custom local domains, `.env` configurations, etc. + +## Release Notes + +Check the file [release-notes.md](./release-notes.md). + +## License + +The Full Stack FastAPI Template is licensed under the terms of the MIT license. From 42bb912deb0c6f45d5551aad45f9e84cb0fb68b4 Mon Sep 17 00:00:00 2001 From: AlfreMu Date: Thu, 15 Jan 2026 16:37:37 -0300 Subject: [PATCH 13/25] feat(docker): agregar docker-compose del portfolio (baseline local) --- docker-compose.portfolio.yml | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 docker-compose.portfolio.yml diff --git a/docker-compose.portfolio.yml b/docker-compose.portfolio.yml new file mode 100644 index 0000000000..e030357e34 --- /dev/null +++ b/docker-compose.portfolio.yml @@ -0,0 +1,49 @@ +services: + db: + image: postgres:17 + restart: unless-stopped + environment: + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changethis} + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_DB: ${POSTGRES_DB:-app} + volumes: + - db-data:/var/lib/postgresql/data + ports: + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 10s + timeout: 5s + retries: 5 + + backend: + build: + context: ./backend + restart: unless-stopped + env_file: + - .env + depends_on: + db: + condition: service_healthy + ports: + - "8000:8000" + + frontend: + build: + context: ./frontend + restart: unless-stopped + depends_on: + - backend + ports: + - "5173:80" + + adminer: + image: adminer + restart: unless-stopped + depends_on: + - db + ports: + - "8080:8080" + +volumes: + db-data: From eb6e39e8c3bf0384c26cd6c6421f768a04910f3f Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Thu, 15 Jan 2026 16:52:15 -0300 Subject: [PATCH 14/25] Update roadmap to mark Phase 1 as complete --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c25f5b52ef..634b76b5d8 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Este repositorio es un **portfolio personal DevOps/Cloud**. El objetivo es demos - Documentación técnica orientada a entrevistas ## Roadmap -- [ ] Phase 1: Docker baseline +- [X] Phase 1: Docker baseline - [ ] Phase 2: Kubernetes local (kind) - [ ] Phase 3: CI/CD - [ ] Phase 4: AWS EC2 + k3s deploy From c10d7646931bd6592a00c819431075585cc9f2bf Mon Sep 17 00:00:00 2001 From: AlfreMu Date: Fri, 16 Jan 2026 16:20:04 -0300 Subject: [PATCH 15/25] feat(k8s): deploy backend en kind cluster --- k8s/portfolio/backend/deployment.yaml | 30 ++++++++++++++++++++++++ k8s/portfolio/backend/env/configmap.yaml | 9 +++++++ k8s/portfolio/backend/env/secret.yaml | 8 +++++++ k8s/portfolio/backend/service.yaml | 12 ++++++++++ kind-config.yaml | 4 ++++ 5 files changed, 63 insertions(+) create mode 100644 k8s/portfolio/backend/deployment.yaml create mode 100644 k8s/portfolio/backend/env/configmap.yaml create mode 100644 k8s/portfolio/backend/env/secret.yaml create mode 100644 k8s/portfolio/backend/service.yaml create mode 100644 kind-config.yaml diff --git a/k8s/portfolio/backend/deployment.yaml b/k8s/portfolio/backend/deployment.yaml new file mode 100644 index 0000000000..e490d1ad3f --- /dev/null +++ b/k8s/portfolio/backend/deployment.yaml @@ -0,0 +1,30 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backend + labels: + app: backend +spec: + replicas: 1 + selector: + matchLabels: + app: backend + template: + metadata: + labels: + app: backend + spec: + containers: + - name: backend + image: devops-portfolio-fastapi-backend:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8000 + env: + - name: PORT + value: "8000" + envFrom: + - configMapRef: + name: backend-config + - secretRef: + name: backend-secret diff --git a/k8s/portfolio/backend/env/configmap.yaml b/k8s/portfolio/backend/env/configmap.yaml new file mode 100644 index 0000000000..424a7e1f1a --- /dev/null +++ b/k8s/portfolio/backend/env/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: backend-config +data: + PROJECT_NAME: "DevOps Portfolio FastAPI" + POSTGRES_SERVER: "db" + POSTGRES_USER: "postgres" + BACKEND_CORS_ORIGINS: '["http://localhost:5173","http://localhost:30080","http://localhost:8000"]' diff --git a/k8s/portfolio/backend/env/secret.yaml b/k8s/portfolio/backend/env/secret.yaml new file mode 100644 index 0000000000..f07d286a36 --- /dev/null +++ b/k8s/portfolio/backend/env/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: backend-secret +type: Opaque +stringData: + FIRST_SUPERUSER: "admin@example.com" + FIRST_SUPERUSER_PASSWORD: "admin123" diff --git a/k8s/portfolio/backend/service.yaml b/k8s/portfolio/backend/service.yaml new file mode 100644 index 0000000000..b54c3595d4 --- /dev/null +++ b/k8s/portfolio/backend/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: backend +spec: + type: NodePort + selector: + app: backend + ports: + - port: 8000 + targetPort: 8000 + nodePort: 30080 diff --git a/kind-config.yaml b/kind-config.yaml new file mode 100644 index 0000000000..f64b87e8e2 --- /dev/null +++ b/kind-config.yaml @@ -0,0 +1,4 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +nodes: + - role: control-plane From 26e036cae6bd124221dced6fc64f46bdcd137a09 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:35:08 -0300 Subject: [PATCH 16/25] Add PostgreSQL deployment configuration --- k8s/portfolio/postgres/deployment.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 k8s/portfolio/postgres/deployment.yaml diff --git a/k8s/portfolio/postgres/deployment.yaml b/k8s/portfolio/postgres/deployment.yaml new file mode 100644 index 0000000000..775fbcb035 --- /dev/null +++ b/k8s/portfolio/postgres/deployment.yaml @@ -0,0 +1,24 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: postgres + labels: + app: postgres +spec: + replicas: 1 + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + spec: + containers: + - name: postgres + image: postgres:17 + ports: + - containerPort: 5432 + envFrom: + - secretRef: + name: postgres-secret From f071882b698d70b9bb8bd020362dfd2b1d7371d7 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:35:22 -0300 Subject: [PATCH 17/25] Add PostgreSQL secret configuration --- k8s/portfolio/postgres/secret.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 k8s/portfolio/postgres/secret.yaml diff --git a/k8s/portfolio/postgres/secret.yaml b/k8s/portfolio/postgres/secret.yaml new file mode 100644 index 0000000000..fd11573938 --- /dev/null +++ b/k8s/portfolio/postgres/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: postgres-secret +type: Opaque +stringData: + POSTGRES_DB: app + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres From 4d630be652411c05b86d4997503496d8a1170b0f Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:35:41 -0300 Subject: [PATCH 18/25] Add Kubernetes Service for Postgres --- k8s/portfolio/postgres/service.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 k8s/portfolio/postgres/service.yaml diff --git a/k8s/portfolio/postgres/service.yaml b/k8s/portfolio/postgres/service.yaml new file mode 100644 index 0000000000..e78c91e198 --- /dev/null +++ b/k8s/portfolio/postgres/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: postgres +spec: + type: ClusterIP + selector: + app: postgres + ports: + - port: 5432 + targetPort: 5432 From d79109ca0120c4b9ab42ccc69d04efd4d5d0610d Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:37:47 -0300 Subject: [PATCH 19/25] Add PersistentVolumeClaim for PostgreSQL --- k8s/portfolio/postgres/pvc.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 k8s/portfolio/postgres/pvc.yaml diff --git a/k8s/portfolio/postgres/pvc.yaml b/k8s/portfolio/postgres/pvc.yaml new file mode 100644 index 0000000000..23afd37855 --- /dev/null +++ b/k8s/portfolio/postgres/pvc.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: postgres-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi From 85b018d8c31b8650e49f99ae7e36c5d90c894574 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:37:58 -0300 Subject: [PATCH 20/25] Add volume mount for PostgreSQL data --- k8s/portfolio/postgres/deployment.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/k8s/portfolio/postgres/deployment.yaml b/k8s/portfolio/postgres/deployment.yaml index 775fbcb035..1c71439f30 100644 --- a/k8s/portfolio/postgres/deployment.yaml +++ b/k8s/portfolio/postgres/deployment.yaml @@ -22,3 +22,10 @@ spec: envFrom: - secretRef: name: postgres-secret + volumeMounts: + - name: postgres-data + mountPath: /var/lib/postgresql/data + volumes: + - name: postgres-data + persistentVolumeClaim: + claimName: postgres-pvc From 1b40eb8d46e1b7570521d1227fe9fbef57592c98 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:40:24 -0300 Subject: [PATCH 21/25] Update PostgreSQL configuration in configmap.yaml --- k8s/portfolio/backend/env/configmap.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/k8s/portfolio/backend/env/configmap.yaml b/k8s/portfolio/backend/env/configmap.yaml index 424a7e1f1a..70254adaeb 100644 --- a/k8s/portfolio/backend/env/configmap.yaml +++ b/k8s/portfolio/backend/env/configmap.yaml @@ -4,6 +4,8 @@ metadata: name: backend-config data: PROJECT_NAME: "DevOps Portfolio FastAPI" - POSTGRES_SERVER: "db" + POSTGRES_SERVER: "postgres" + POSTGRES_PORT: "5432" + POSTGRES_DB: "app" POSTGRES_USER: "postgres" - BACKEND_CORS_ORIGINS: '["http://localhost:5173","http://localhost:30080","http://localhost:8000"]' + BACKEND_CORS_ORIGINS: '["http://localhost:5173","http://localhost:18000"]' From 1d54363fcaf370d215dcbdcf3dd86cce7c48efe1 Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:40:37 -0300 Subject: [PATCH 22/25] Add POSTGRES_PASSWORD to backend-secret --- k8s/portfolio/backend/env/secret.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/k8s/portfolio/backend/env/secret.yaml b/k8s/portfolio/backend/env/secret.yaml index f07d286a36..074bd4664d 100644 --- a/k8s/portfolio/backend/env/secret.yaml +++ b/k8s/portfolio/backend/env/secret.yaml @@ -4,5 +4,6 @@ metadata: name: backend-secret type: Opaque stringData: + POSTGRES_PASSWORD: "postgres" FIRST_SUPERUSER: "admin@example.com" FIRST_SUPERUSER_PASSWORD: "admin123" From 5e6ea1ec9bb2a5d5283c3c1431782cc6012d2c3d Mon Sep 17 00:00:00 2001 From: AlfreMu Date: Fri, 16 Jan 2026 16:58:50 -0300 Subject: [PATCH 23/25] chore(ci): mover workflows upstream fuera de .github/workflows --- .github/{workflows => workflows_upstream}/add-to-project.yml | 0 .github/{workflows => workflows_upstream}/deploy-production.yml | 0 .github/{workflows => workflows_upstream}/deploy-staging.yml | 0 .github/{workflows => workflows_upstream}/detect-conflicts.yml | 0 .github/{workflows => workflows_upstream}/generate-client.yml | 0 .github/{workflows => workflows_upstream}/issue-manager.yml | 0 .github/{workflows => workflows_upstream}/labeler.yml | 0 .github/{workflows => workflows_upstream}/latest-changes.yml | 0 .github/{workflows => workflows_upstream}/playwright.yml | 0 .github/{workflows => workflows_upstream}/pre-commit.yml | 0 .github/{workflows => workflows_upstream}/smokeshow.yml | 0 .github/{workflows => workflows_upstream}/test-backend.yml | 0 .github/{workflows => workflows_upstream}/test-docker-compose.yml | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => workflows_upstream}/add-to-project.yml (100%) rename .github/{workflows => workflows_upstream}/deploy-production.yml (100%) rename .github/{workflows => workflows_upstream}/deploy-staging.yml (100%) rename .github/{workflows => workflows_upstream}/detect-conflicts.yml (100%) rename .github/{workflows => workflows_upstream}/generate-client.yml (100%) rename .github/{workflows => workflows_upstream}/issue-manager.yml (100%) rename .github/{workflows => workflows_upstream}/labeler.yml (100%) rename .github/{workflows => workflows_upstream}/latest-changes.yml (100%) rename .github/{workflows => workflows_upstream}/playwright.yml (100%) rename .github/{workflows => workflows_upstream}/pre-commit.yml (100%) rename .github/{workflows => workflows_upstream}/smokeshow.yml (100%) rename .github/{workflows => workflows_upstream}/test-backend.yml (100%) rename .github/{workflows => workflows_upstream}/test-docker-compose.yml (100%) diff --git a/.github/workflows/add-to-project.yml b/.github/workflows_upstream/add-to-project.yml similarity index 100% rename from .github/workflows/add-to-project.yml rename to .github/workflows_upstream/add-to-project.yml diff --git a/.github/workflows/deploy-production.yml b/.github/workflows_upstream/deploy-production.yml similarity index 100% rename from .github/workflows/deploy-production.yml rename to .github/workflows_upstream/deploy-production.yml diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows_upstream/deploy-staging.yml similarity index 100% rename from .github/workflows/deploy-staging.yml rename to .github/workflows_upstream/deploy-staging.yml diff --git a/.github/workflows/detect-conflicts.yml b/.github/workflows_upstream/detect-conflicts.yml similarity index 100% rename from .github/workflows/detect-conflicts.yml rename to .github/workflows_upstream/detect-conflicts.yml diff --git a/.github/workflows/generate-client.yml b/.github/workflows_upstream/generate-client.yml similarity index 100% rename from .github/workflows/generate-client.yml rename to .github/workflows_upstream/generate-client.yml diff --git a/.github/workflows/issue-manager.yml b/.github/workflows_upstream/issue-manager.yml similarity index 100% rename from .github/workflows/issue-manager.yml rename to .github/workflows_upstream/issue-manager.yml diff --git a/.github/workflows/labeler.yml b/.github/workflows_upstream/labeler.yml similarity index 100% rename from .github/workflows/labeler.yml rename to .github/workflows_upstream/labeler.yml diff --git a/.github/workflows/latest-changes.yml b/.github/workflows_upstream/latest-changes.yml similarity index 100% rename from .github/workflows/latest-changes.yml rename to .github/workflows_upstream/latest-changes.yml diff --git a/.github/workflows/playwright.yml b/.github/workflows_upstream/playwright.yml similarity index 100% rename from .github/workflows/playwright.yml rename to .github/workflows_upstream/playwright.yml diff --git a/.github/workflows/pre-commit.yml b/.github/workflows_upstream/pre-commit.yml similarity index 100% rename from .github/workflows/pre-commit.yml rename to .github/workflows_upstream/pre-commit.yml diff --git a/.github/workflows/smokeshow.yml b/.github/workflows_upstream/smokeshow.yml similarity index 100% rename from .github/workflows/smokeshow.yml rename to .github/workflows_upstream/smokeshow.yml diff --git a/.github/workflows/test-backend.yml b/.github/workflows_upstream/test-backend.yml similarity index 100% rename from .github/workflows/test-backend.yml rename to .github/workflows_upstream/test-backend.yml diff --git a/.github/workflows/test-docker-compose.yml b/.github/workflows_upstream/test-docker-compose.yml similarity index 100% rename from .github/workflows/test-docker-compose.yml rename to .github/workflows_upstream/test-docker-compose.yml From e5abc3f412994c7b162d1a734c98dae52038f80c Mon Sep 17 00:00:00 2001 From: AlfreMu Date: Fri, 16 Jan 2026 17:11:07 -0300 Subject: [PATCH 24/25] ci: agregar workflow de build (backend y frontend) --- .github/workflows/ci.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..180c63b5a4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,37 @@ +name: CI + +on: + pull_request: + branches: [ "main" ] + push: + branches: [ "main" ] + +jobs: + docker-build: + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + fail-fast: false + matrix: + service: + - name: backend + context: ./backend + - name: frontend + context: ./frontend + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build ${{ matrix.service.name }} + uses: docker/build-push-action@v6 + with: + context: ${{ matrix.service.context }} + push: false + tags: devops-portfolio/${{ matrix.service.name }}:ci + cache-from: type=gha + cache-to: type=gha,mode=max From 5c62e7443205ef8f8147ff6f55a8dae13953959b Mon Sep 17 00:00:00 2001 From: AlfreMu <141455009+AlfreMu@users.noreply.github.com> Date: Fri, 16 Jan 2026 17:24:00 -0300 Subject: [PATCH 25/25] Add CI badge to workflows README Added CI badge to workflows README. --- .github/workflows/README.MD | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/README.MD b/.github/workflows/README.MD index 65569ccd35..7e97cdf01d 100644 --- a/.github/workflows/README.MD +++ b/.github/workflows/README.MD @@ -1,3 +1,5 @@ +![CI](https://github.com/AlfreMu/devops-portfolio-fastapi/actions/workflows/ci.yml/badge.svg) + # Workflows (portfolio) Workflows del portfolio: