Skip to content


PROJECT DETAILS


Demizona E-Commerce MVP


Team capstone of the "Emprendimiento digital con Tecnologías web" bootcamp (Le Wagon / Talento Digital para Chile): an e-commerce MVP that lets local producers publish and sell their products online, built and deployed as a full-stack Ruby on Rails application.
Six people developed it collaboratively on a shared Git workflow — branches, pull requests and code reviews — which makes this the only project in this portfolio with verifiable team collaboration in code; every other project here was individual work. It is also the only project outside the Python ecosystem.
My role centered on the product review system: AJAX-submitted reviews, the star-rating input and its styling (57 commits, publicly attributable in the repository history).

Framework: Ruby On Rails

Demizona E-Commerce MVP

Technology Stack:

Ruby / HTML / CSS / JAVASCRIPT / BOOTSTRAP


About Team

Company / Institution: Le Wagon / Talento Digital — Bootcamp Team Capstone

Developer: Team of 6 (dekaacevedo, pabloems, maaferna, jorgemolinan, sbuffose, Javieratapiab). My contribution — 57 of 376 commits, third contributor — focused on the product review system: AJAX submission, star ratings and their styling.

My commits in this team project (57)

Team capstone with 6 contributors — the commit history filtered by my authorship is publicly verifiable in the shared repository.



Project Images


Show Code


views.py Code

@throttle_classes([TenCallsPerMinute])
def projects_rendering(request, project_id):
    # Una ficha inexistente devolvía 500 (el .get() lanzaba DoesNotExist): 107 ids
    # sin proyecto servían la página desnuda de Django en vez del 404 del sitio.
    project = get_object_or_404(Project, id=project_id)
    projects = Project.objects.exclude(title_en='My Portfolio').exclude(status='archived')
    # image_logo admite NULL (blank=True, null=True) y os.path.basename(None) lanza
    # TypeError: una ficha creada en el admin sin logo devolvía 500. Sin logo, la
    # plantilla omite la <img>.
    logo = extract_filename_from_path(project.image_logo) if project.image_logo else ''

    # Galería y endpoints salen de datos, no de código: el prefijo del proyecto
    # (slug del repositorio, o el mapa de los proyectos antiguos) y lo que existe en
    # static/img y endpoints.json. Publicar un proyecto nuevo es crear la ficha en el
    # admin y dejar <slug>1.svg, <slug>2.svg… en static/img.
    prefix = gallery_prefix(project)
    with open(os.path.join(settings.STATICFILES_DIRS[0], 'json', 'endpoints.json')) as file:
        all_endpoints = json.load(file)
    # Sin prefijo, startswith('') aceptaría las rutas de todos los proyectos.
    endpoints = {key: value for key, value in all_endpoints.items() if prefix and key.startswith(prefix)}

    project.website = patch_url(project.website)
    project.repository = patch_url(project.repository)

    # Artículos del blog sobre este proyecto: uno por artículo, en el idioma activo si
    # existe (la misma regla que el listado del blog). Import local: blog ya depende de
    # portfolio (Post.project) y así no se forma un ciclo al cargar los módulos.
    from blog.models import pick_language
    related_posts = pick_language(
        project.posts.filter(published_at__lte=timezone.now()), get_language()
    )

    context = {
        'project': project,
        'projects': projects,
        'related_posts': related_posts,
        'path_images': gallery_images(project),
        'logo': logo,
        'endpoints': endpoints,
        'og_image_static': share_image(project),
        **show_code([projects_rendering], 'project.html'),
    }
    return render(request, 'project.html', context)

Template

{% extends 'base.html' %}
{% load i18n static %}
{# Título, descripción e imagen de la ficha: sin esto las diez fichas se compartían con el título genérico del sitio. #}
{% block title %}{{ project.title }} | Marco A. Parra F.{% endblock %}
{% block meta_description %}{{ project.description|striptags|truncatechars:160 }}{% endblock %}
{% block og_title %}{{ project.title }}{% endblock %}
{% block og_description %}{{ project.description|striptags|truncatechars:200 }}{% endblock %}
{% block og_image %}{% if og_image_static %}{{ request.scheme }}://{{ request.get_host }}{% static og_image_static %}{% else %}{{ block.super }}{% endif %}{% endblock %}
{% block twitter_card %}{% if og_image_static %}summary_large_image{% else %}summary{% endif %}{% endblock %}
{% block structured_data %}{{ block.super }}
    <script type="application/ld+json">
    {"@context": "https://schema.org", "@type": "SoftwareSourceCode", "name": "{{ project.title|escapejs }}", "description": "{{ project.description|striptags|truncatechars:300|escapejs }}", "url": "{{ canonical_url|escapejs }}",{% if project.repository %} "codeRepository": "{{ project.repository|escapejs }}",{% endif %} "programmingLanguage": "{{ project.technology|escapejs }}", "inLanguage": "{{ LANGUAGE_CODE }}", "author": {"@id": "{{ request.scheme }}://{{ request.get_host }}/#person"}}
    </script>
{% endblock %}
{% block content %}
{% load static %}
{% load fontawesome_5 %}
{% load cached_pygments %}
<br><br>
<section class="container-section mb-4">
    <div class="container-fluid">
        <div class="row g-0">
            <div class="portfolio-box-caption">
                <div class="row">
                    <div class="col">
                        <h2 class="portfolio-box-headers" style="text-align:center">
                           {% trans "PROJECT DETAILS" %}</h2>
                    </div>
                </div>
            </div>
            <hr>

            <div class="container">
                <div class="row" >
                    <div class="container-fluid specialization-detail" style="background: white">
                        <div class="row mb-4">
                            <h3 class="mt-9" style="margin:10px">{{ project.title }}</h3>
                        </div>
                        <hr>
                        <div class="row mb-4">
                            <p  class="d-none d-sm-block show-read-more" style="margin:10px">{{ project.description|linebreaksbr }}</p>
                        </div>
                        <div class="row mb-4">
                            <div class="col-12 col-sm-10">
                                <h4>{% trans "Framework:" %} <strong> {{project.technology|linebreaksbr}}</strong></h4>
                            </div>
                            {% if logo %}
                                <div class="col">
                                    <img class="mw-100" style="height: 3em" src="{% static 'img/' %}{{ logo }}" alt="{{project.title}}" />
                                </div>
                            {% endif %}
                        </div>
                        <div class="row mb-4">
                            <hr>
                            <h6>{% trans "Technology Stack:" %}</h6>
                            <p style="white-space: pre-wrap;">{{project.technology_stack|linebreaksbr}}</p>
                            <hr>
                        </div>
                        <div class="row mb-4">
                            <h4>{% trans "About Team" %}</h4>
                            <div class="row">
                                <div class="col-12 col-md-6">
                                    <p><strong>Company / Institution: </strong>{{project.organizations}}</p>
                                </div>
                                <div class="col-12 col-md-6">
                                    <p><strong>{% trans "Developer:" %} </strong>{{project.developers}}</p>
                                </div>
                            </div>
                        </div>
                        {% if project.website and project.website != 'Not Available' and project.website != '' %}
                        <div class="row mb-3">
                            {% if project.id == 4 or project.id == 9 %}
                            <div class="col-12 col-sm-6 mb-3 mb-sm-0">
                                <button class="btn btn-warning rounded-0"><a href="{{ project.website }}" target="_blank" style="font-size: 2em">Server Side Repo</a></button>
                            </div>
                            {% else %}
                            <div class="col-12 col-sm-6 mb-3 mb-sm-0">
                                <button class="btn btn-warning rounded-0"><a href="{{ project.website }}" target="_blank" style="font-size: 2em">{% trans "Go To Website" %}</a></button>
                            </div>
                            {% endif %}
                            {% if project.id != 2 %}
                            <div class="col-12 col-sm-6 mb-3 mb-sm-0">
                                <button class="btn btn-warning rounded-0"><a href="{{ project.repository }}" target="_blank" style="font-size: 2em">Go To Repository</a></button>
                            </div>
                            {% endif %}
                        </div>
                        {% endif %}
                        {% if project.id == 1 %}
                        <div class="row mb-3">
                            <div class="col-12">
                                <a class="btn btn-warning rounded-0" href="https://github.com/dekaacevedo/demizona/commits/master/?author=maaferna" target="_blank">
                                    <i class="fab fa-github me-1"></i>My commits in this team project (57)
                                </a>
                                <p class="text-muted small mt-2 mb-0">
                                    Team capstone with 6 contributors — the commit history filtered by my authorship
                                    is publicly verifiable in the shared repository.
                                </p>
                            </div>
                        </div>
                        {% endif %}
                        {% if project.id == 9 or project.id == 42 or project.id == 75 %}
                        <div class="row mb-3">
                            <div class="col-12">
                                <a class="btn btn-warning rounded-0" href="{{ project.repository }}" target="_blank">
                                    <i class="fab fa-github me-1"></i>Case study repository
                                </a>
                                <p class="text-muted small mt-2 mb-0">
                                    The repository documents the problem, architecture and results of this case study.
                                    Source code is not published{% if project.id != 9 %} (confidential, anonymized professional work){% endif %}.
                                </p>
                            </div>
                        </div>
                        {% elif project.id == 108 or project.id == 111 %}
                        {% comment %}
                        Case studies solo documentales sin demo (108 y control dimensional): el
                        bloque de arriba oculta los botones cuando no hay website.
                        La condición era «not project.website and project.repository», y capturaba
                        cualquier ficha sin sitio: la 1 (Demizona) publicaba «No source code is
                        published» sobre un repositorio de bootcamp que sí tiene código, y con el
                        botón apuntando al perfil de GitHub, no a un repo. Se enumeran los ids,
                        como hace la rama de arriba con 9/42/75.
                        {% endcomment %}
                        <div class="row mb-3">
                            <div class="col-12">
                                <a class="btn btn-warning rounded-0" href="{{ project.repository }}" target="_blank">
                                    <i class="fab fa-github me-1"></i>{% trans "Case study repository" %}
                                </a>
                                <p class="text-muted small mt-2 mb-0">
                                    {% trans "Documentation-only repository: problem, method, architecture and limits. No source code or client data is published." %}
                                </p>
                            </div>
                        </div>
                        {% elif project.repository and not project.website and project.id != 1 %}
                        {% comment %}
                        Cualquier ficha nueva sin demo: sin esta rama, la cadena por ids de arriba la
                        dejaba sin ningún enlace al repositorio. Texto neutro, sin afirmar que no hay
                        código; la 1 (Demizona) tiene su propio botón a los commits.
                        {% endcomment %}
                        <div class="row mb-3">
                            <div class="col-12">
                                <a class="btn btn-warning rounded-0" href="{{ project.repository }}" target="_blank">
                                    <i class="fab fa-github me-1"></i>{% trans "Public repository" %}
                                </a>
                            </div>
                        </div>
                        {% endif %}
                        {% if project.id == 8 %}
                        <div class="row mb-3">
                            <div class="col-12">
                                <a class="btn btn-warning rounded-0" href="{% url 'todo_demo' %}">
                                    <i class="fas fa-play me-1"></i>{% trans "Try the live demo (no account needed)" %}
                                </a>
                                <p class="text-muted small mt-2 mb-0">
                                    {% trans "The running app is the <code>todo_app</code> module of this portfolio (Django + DRF, session auth, AJAX). The linked repository is the original 2023 standalone version (Django REST + Vue), kept archived for reference." %}
                                </p>
                            </div>
                        </div>
                        {% endif %}
                        {% if project.id == 2 %}
                        <div class="row mb-3">
                            <div class="col-12">
                                <a class="btn btn-warning rounded-0" href="{% url 'parts' %}">
                                    <i class="fas fa-route me-1"></i>{% trans "Technical deep-dive: routes &amp; endpoints" %}
                                </a>
                            </div>
                        </div>
                        {% endif %}
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>

{% block certificates %}
    {% include 'partials/carousel_images.html' %}
{% endblock %}

{# Artículos del blog sobre este proyecto (Post.project), en el idioma activo si existe. #}
{% if related_posts %}
{% get_current_language as CURRENT_LANGUAGE %}
<section class="container-section mb-4" id="related-articles">
    <div class="container-fluid">
        <div class="row g-0">
            <div class="portfolio-box-caption">
                <h2 class="portfolio-box-headers text-center">{% trans "Related articles" %}</h2>
            </div>
            <hr>
            <div class="container mb-4">
                <ul class="list-unstyled mb-0">
                    {% for post in related_posts %}
                    <li class="py-2 border-bottom">
                        <a href="{% url 'blog-post-detail' post.slug %}" class="fw-semibold">{{ post.title }}</a>
                        {% if post.language != CURRENT_LANGUAGE %}<span class="badge bg-secondary align-middle ms-1">{{ post.language|upper }}</span>{% endif %}
                        <p class="text-muted small mb-0">{{ post.summary|truncatewords:30 }}</p>
                    </li>
                    {% endfor %}
                </ul>
            </div>
        </div>
    </div>
</section>
{% endif %}

{# Sólo si endpoints.json tiene entradas para este proyecto: un caso de estudio o una CLI no tiene rutas HTTP, y la tabla vacía (fichas 9, 42 y 111) parecía un error. Antes se ocultaba por id, y cada ficha nueva la mostraba vacía. #}
{% if endpoints %}
<section class="container-section mb-4">
    <div class="container-fluid">
        <div class="row g-0">
            <div class="portfolio-box-caption">
                <div class="row">
                    <div class="col">
                        <h2 class="portfolio-box-headers" style="text-align:center">
                           <i class="fas fa-route"></i> {% trans "Endpoints &amp; Routes" %}</h2>
                    </div>
                </div>
            </div>
             <hr>
            <div class="container mb-4" id="Endpoint">
                <h3 class="mb-3 mt-4 p-4" style="background-color: #212529; color: #fff;"><i class="fas fa-list"> Available EndPoints</i></h3>
                {% if project.id == 3 %}
                <p>
                    In this project,  only a few available endpoint is displayed, in the section <strong>Available EndPoint</strong> there are displayed. To see the complete code can visit the original repository.
                </p>
                {% endif %}
                <div class="row">
                    <div class="col table-responsive">
                        <table class="table table-hover align-middle">
                            <thead class="table-dark">
                              <tr>
                                    <th scope="col">{% trans "Endpoint" %}</th>
                                    <th scope="col">{% trans "Description" %}</th>
                                    <th scope="col">URL</th>
                                </tr>
                            </thead>
                            <tbody>
                                {% for key, values in endpoints.items %}
                                {% for items in endpoints.values %}
                                {% for value in items %}
                                <tr>
                                    <td> {{ value.endpoint }}</td>
                                    <td>{{ value.description|linebreaksbr }}</td>
                                    <td>
                                        <a class="btn btn-success btn-sm rounded-0" href="{{ value.href }}" target="_blank" rel="noopener" aria-label="{% trans "Open" %} {{ value.endpoint }}"><i class="fa fa-edit" aria-hidden="true"></i></a>
                                    </td>
                                </tr>
                                {% endfor %}
                                {% endfor %}
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>
{% endif %}

{% include 'partials/_show_code.html' %}
{% endblock %}