Portrait of Alexis Misslin
Montréal

Experience

Efipeek

APRIL 2023 — APRIL 2026

Symfony developer

During my three years at Efipeek, I worked primarily on Carter-Cash’s e-commerce platform. My work spanned Symfony backend development and interfaces, from understanding requirements to supporting releases in production.

La Bouclup’

MARCH 2021 — JULY 2022

Co-founder · Product & web development

Entrepreneurial project

My cofounder and I developed a vintage and upcycled clothing rental concept, primarily as a subscription box. I was involved across the business and built the first web MVP. With support from EuraTechnologies and 1Kubator, we reached that first MVP before deciding to stop the project ahead of launch.

From the concept to how the service would work

Shaping the offer together

La Bouclup’ was a project built by two co-founders around the rental of vintage and upcycled outfits, primarily through a subscription box. What began as the straightforward idea of renting clothes gradually grew into a broader reflection on how we dress.

My cofounder and I worked across the whole project: shaping the offer, defining how the service would work and turning those decisions into a first MVP. I was responsible for building that web MVP.

Working out how the service would run

The lifecycle of an outfit brought together many of the project’s core questions:

  1. Rental
  2. Return
  3. RestockingInspection & cleaning
  4. Availability

The longer-term goal was to combine the expected return date with preparation time to anticipate when an outfit would become available again and allow it to be reserved for a future box.

This made the connection between a product rule and its technical implementation tangible.

Developing the project with incubator support

Two incubation programs supported us as the project matured:

  • EuraTechnologiesMay — July 2021
  • 1KubatorApril — June 2022

These programs helped us sharpen the concept, develop the business model, challenge our assumptions, and prepare the pitch and go-to-market approach.

A lasting instinct: bridging product and engineering

~/efipeek/Carter-Cash

Three years working on Carter-Cash

Selected work from my time at Efipeek. Choose a topic to explore the problem, my contribution and the technical decisions.

01Building the online returns journeyFrom requirements to production, this folder covers the returns workflow, its business rules, its Symfony implementation, and its use by customer service. 02Connecting orders to DatahubThis folder presents the Datahub integration: order transformation, asynchronous exchanges, traceable failures, and monitoring tools for operational teams. 03Taking over authentication and reconciling accountsFrom taking over Auth0 to merging identities, this folder covers the Symfony integration, security, and the customer account lifecycle.

Other contributions

04Keeping carts across devicesThis folder traces cart continuity across sessions and devices, the preservation of store context, and its implementation with Symfony and Doctrine. 05Improving search and product availabilityFrom automotive compatibility to availability, this folder covers search rules, catalog data, Algolia, and their presentation in the interfaces. 06Addressing reliability risks earlyFrom risk prevention to regression testing, this folder covers reference generation, data maintenance, and operational tooling.

Building the online returns journey

From initial requirements to a workable solution

Carter-Cash wanted to let customers initiate returns online. The initial request defined the goal and considered using a logistics platform, but the workflow, its rules, and its technical feasibility still needed to be worked out.

Working with the Carter-Cash project manager, who represented the business and customer service teams, I explored the Woop API and tested the initial ideas against the site’s constraints. I identified what was feasible, proposed the necessary adjustments, filled in the remaining business rules, and then designed and built the web workflow.

Making complex returns feel simple

A return did not always map to a single delivery. Products could ship separately, arrive on different dates, or be divided across several packages. The rules also changed depending on whether the customer wanted to return the items remotely or at a store.

I translated these situations into a workflow that identifies eligible products, groups them by their original delivery, and creates as many returns and shipping labels as needed. Each step adapts to the customer’s choice: store selection appears only for in-store returns, while split deliveries and multi-package orders are handled by the system.

Technical decisions

Backend with Symfony

Controllers, forms, custom validators, domain services, and Doctrine entities handle return creation, validate the selected products, and group them by their original delivery.

API and asynchronous processing

Dedicated HTTP services manage communication with Woop, including authentication, error handling, and logging. When a shipping label was not immediately available, Symfony Messenger continued retrieving it without blocking the customer’s journey.

Interfaces and documents

Twig screens, supported by JavaScript, jQuery, and SCSS, dynamically adjust the available choices. Return slips and shipping labels are generated from templates, converted to PDF, and then made available to the customer or attached to the relevant communications.

Testing and reliability

PHPUnit tests cover domain services, grouping rules, and the objects exchanged with the APIs. They complement detailed test plans, functional acceptance testing, and error monitoring after release.

One service, regardless of the entry point

The online returns workflow could not cover every situation. A customer might encounter an issue on the site or need direct assistance from customer service to create a return.

In a later iteration, I designed APIs for the internal tool used by customer service agents. They can retrieve the required information and create a return from their own interface while reusing the same services and business rules as the web workflow. Customers and agents therefore follow the same rules, even when the return starts from a different interface.

Owning the solution through production

I supported each update to the returns workflow through release: preparing test data and test plans, running acceptance testing with Carter-Cash and its customer service team, verifying exchanges with the connected systems, and monitoring the production deployment.

Once the solution was live, incidents and change requests related to returns were consistently assigned to me. I investigated their causes, implemented the required fixes, and adjusted the rules in collaboration with Carter-Cash project management. I remained the technical point person for this area until I left the project.

Connecting orders to Datahub

Turning data exchange requirements into a technical solution

Carter-Cash wanted to send its orders to Datahub. Behind that goal was a set of information distributed across the existing model: orders, shipments, customers, stores, products, pricing, history, and fulfillment methods.

I analyzed these sources, identified the required information, and defined how it should be transformed into Datahub’s expected format. I then designed the complete exchange, from the triggering event in the order lifecycle to the construction and authenticated delivery of the data.

Moving data without blocking the application

Datahub delivery could not run directly during a customer action or an important business transition. A slow response or service outage could otherwise block the site unnecessarily.

I chose an asynchronous architecture based on Symfony Messenger. When an order reaches the relevant state, a message is placed on a dedicated queue. A worker later processes it independently, reloads the required information, and sends it to Datahub. The action that triggered the exchange can therefore complete normally, even when the external service is slow or unavailable.

Never letting a data flow fail silently

An asynchronous Datahub delivery can fail long after the order event that triggered it. Without dedicated tracking, an order’s data might never reach the service, while the failure remained difficult to see or reproduce.

I implemented persistent failure tracking for each affected shipment, including the returned status, number of attempts, and date of the latest attempt. Dedicated logs also retain the trigger source and context required for diagnosis. When a later delivery succeeds, the previously recorded failure is automatically cleared.

Making integrations visible and actionable

Datahub delivery monitoring could not rely on logs alone. Access would have remained limited to developers, and incidents would have been difficult to find over time. I therefore proposed a dedicated back-office interface where failed processes are directly visible.

The view brings together the information needed for diagnosis: the related order, shipment, status, failure count, and latest attempt. An action lets the delivery be retried manually through the same service used by the automatic process. A successful retry clears the error; otherwise, its tracking is updated.

Technical decisions

Construction and delivery

A builder transforms orders and their shipments into the expected format. A client built on Symfony HttpClient obtains an access token, sends the data, and interprets the external service’s response.

Asynchronous processing

A change in order state dispatches a Symfony Messenger message. A handler then reloads the shipment and delegates delivery to a shared service that is also used for manual retries.

Errors and operations

Doctrine persists failures and their attempts, while a dedicated Monolog channel provides technical context. Sonata Admin exposes this information and lets users retry a delivery without duplicating business logic.

Other integrations

I also explored the Woop API to replace a legacy source of pickup locations. I identified the required data: location, pickup-point identity, opening hours, and accepted package categories, then completed most of the integration into the delivery journey.

Taking over authentication and reconciling accounts

Becoming the point person for an existing system

Auth0 was already handling customer authentication when I joined the project. I had not taken part in its initial implementation, but account and sign-in incidents gradually led me to work in this area on a regular basis.

I used the Auth0 console to inspect identities, diagnose access issues, and help users regain access. By repeatedly handling these requests and connecting the service’s behavior with the Symfony application, I became the team’s operational point person for Auth0.

Taking over and completing the Symfony integration

Following several security initiatives, the team decided to integrate Auth0’s official Symfony bundle. Another developer had started the work, but their departure left an initial version that was incomplete and only partly adapted to the site.

I took over that foundation, identified the remaining journeys and edge cases, and adapted the integration to the existing application. I completed the missing pieces, removed legacy mechanisms that were no longer needed, and brought the work to a final version ready for deployment.

Securing account creation and lifecycle

Adding an authentication security rule never affected sign-in alone. Account verification, for example, could also affect existing customers, the post-registration journey, error messages, and the ability to resend required communications.

I assessed these impacts and documented the business decisions required before new protections could be enabled. I then developed the Auth0 Actions and triggers, along with the Symfony endpoints needed for the selected registration checks. I also adapted session and logout handling to maintain a consistent lifecycle between Auth0 and the application.

Merging identities without losing their history

The authentication changes required handling customers who had several accounts for the same identity. Simply deleting one could remove part of their history or leave inconsistent relationships between the application and Auth0.

I designed and built a process that detects duplicates, selects the primary account based on activity, and transfers related orders, carts, addresses, vehicles, and relevant preferences to that account. Accounts that are no longer needed are then removed locally and from Auth0 where required. Locks, execution limits, dedicated logs, and summaries make each merge controllable.

Technical decisions

Symfony authentication

The bundle integrates with the Security component through providers, an authenticator, an entry point, and dedicated subscribers. I adapted these components to the application’s different profiles and existing journeys, then removed legacy mechanisms that were no longer needed.

Auth0 lifecycle

Auth0 Actions and triggers communicate with Symfony controllers to apply the required checks during registration. Logout, session, and identifier management were also adapted to keep Auth0 and the application in a consistent state.

Account migration

A Symfony command uses Doctrine and the Auth0 API to merge duplicate accounts, transfer related data, and delete identities that are no longer needed. Locks, execution limits, and dedicated logs protect the operation.

Production release

I was directly involved in the production rollout during a planned window designed to limit customer impact. The new Auth0 foundation, required Actions, and account merge were verified before the full journey was reopened.

Keeping carts across devices

Resuming a cart on any device

Originally, the cart relied mainly on the browser session. After a period of inactivity, signing back in, or moving to another device, customers could lose their active cart and have to start over.

I redesigned cart initialization so it no longer depended only on that session. When a customer signs in, the system can retrieve their latest valid cart from the database and restore it to the journey. If no cart can be resumed, a new one is created for the customer’s current context.

Reconciling cart, identity, and store

Several states could exist at sign-in: an anonymous cart in the current session, an earlier cart still active in the database, or a store that differed from the one previously associated with the customer. Sales associate accounts also required behavior distinct from standard customer accounts.

I structured the rules used to resolve these situations. An anonymous cart can be assigned to the customer who has just signed in; when none exists, the latest valid cart is retrieved. The cart’s store and the session’s store are then synchronized according to context. Customers recover their shopping environment, while sales associate use remains isolated in a dedicated cart.

Understanding cross-device journeys

Cart continuity allowed customers to keep shopping, but it also raised a new question: how did a journey that began on mobile, desktop, or tablet progress through to the order?

I designed tracking for the devices used at key stages of the cart: creation, device change, entry into payment, and completion. Rules ensure that only consistent transitions are recorded, and an aggregated view makes the main cross-device journeys available for analysis. I supported this feature through its production release.

Technical decisions

Cart initialization

A central Symfony service coordinates the different cases: a cart already in the session, assigning an anonymous cart after sign-in, retrieving the latest valid cart, or creating a new one. A Doctrine repository selects the reusable cart based on the state of its related order.

Identity and store context

The rules explicitly distinguish customers from sales associates. The cart also retains its store so a resumed journey can reconcile the saved context with the new session.

Event-driven tracking

EventDispatcher decouples device logging from the main business journey. Events are dispatched at meaningful stages, then a service applies integrity rules, detects the device type, and records only relevant transitions. A SQL view aggregates completed journeys.

Testing and reliability

PHPUnit covers the main initialization scenarios: creation, assignment after sign-in, database retrieval, and sales-associate-specific handling. Security, session, repository, and Doctrine dependencies are mocked to isolate the business rules.

Improving search and product availability

Helping customers find the right product

Choosing a tire involves more than matching its dimensions. Load and speed ratings, season, and Runflat technology all determine compatibility, with different rules for summer, winter, and all-season tires.

As part of an update developed with the team, I helped translate these rules into Algolia filters: comparing ratings, adapting criteria by season, and handling compatible products even when some attributes differed from the initial search. I also worked on the information shown to explain those differences, then verified result consistency using Algolia queries and a functional test plan.

Showing availability customers can rely on

On a site connected to physical stores and several supply sources, availability is more than an inventory count. It also depends on the selected store, ordering options, product characteristics, and whether the customer chooses pickup or delivery.

I helped update these rules and how they were presented throughout the journey. I adapted the use of new inventory, pricing, and availability data provided by Algolia. In a later change, I also centralized the permitted fulfillment options in a Symfony service and added server-side validation so the available choices remained consistent through the cart.

Evolving a legacy catalog

The catalog had grown over time around several data sources. Depending on the product type, country, or screen, information could come from Algolia, external catalog services, or the database. A change to a single attribute could therefore affect search, pricing, availability, analytics, or the final display.

My work often involved taking over work already in progress, identifying its impact across the codebase, and adapting the affected layers. I worked on new Algolia attributes, country-specific behavior, sorting and pagination, availability messages, and fallback values for missing data. Each change required checking several sources and screens, not only the place where the request originated.

Technical decisions

Search and filtering

Symfony services build Algolia filters and facets based on product attributes, vehicle, store, and country. I updated these rules as well as sorting and pagination, particularly for the Tire Selector and product listings.

Display and interactions

Results, active filters, and autocomplete suggestions are rendered with InstantSearch.js, JavaScript, and Twig. The components adapt prices, availability, compatibility information, and available actions to the customer’s context.

Data and availability

The journey combines data from Algolia, catalog APIs, and Doctrine. I adapted the mappings between these sources, added fallback values for missing attributes, and centralized selected availability rules in reusable Symfony services with server-side validation.

Validation and monitoring

Results were checked with Algolia queries, functional test plans, and acceptance testing on the site. Logs and analytics supported diagnosis when a listing or search did not behave as expected.

Addressing reliability risks early

Addressing a risk before it became an incident

Order, shipment, and product references were derived from part of their global identifiers. As volume increased, this mechanism could reuse an earlier value and create a collision. A temporary fix had delayed the problem without removing its cause.

After the risk was raised during a daily meeting, I analyzed the existing mechanism and the many components that depended on these references. I compared several strategies, presented their tradeoffs, and recommended an architecture based on dedicated counters by store, use case, and period. Once the approach was approved, I implemented it with the protections required for concurrent creation.

Maintaining data before it accumulates

I noticed that many obsolete carts remained in the database indefinitely. I raised the issue, then proposed and designed their cleanup without an initial client request. I later designed a similar process for a recurring need involving old redirects.

Both processes distinguish data that is still useful from data that can be removed, then work in batches to limit their impact. Locks, maximum runtimes, logs, execution histories, and email summaries make each run traceable, while scheduled execution maintains the cleanup over time.

Treating regression prevention as part of the job

On an e-commerce platform, a regression can prevent a search, sign-in, or order from completing. Because many rules were interconnected, verifying behavior was an integral part of my development work.

I prepared detailed test plans, ran functional acceptance tests, and added PHPUnit coverage for sensitive services and business rules. Together with Vincent, I also helped create a Cypress project covering many end-to-end journeys. The project was run manually when needed; it was not yet a systematic or fully automated test pipeline.

Technical decisions

Reference generation

To replace the earlier mechanism based on part of the global identifiers, I created a shared generation service for orders, shipments, and ordered products. Each store has its own counters, separated by reference type and period.

Concurrent creation

Doctrine guarantees the uniqueness of each counter. When simultaneous requests attempt to use the same value, optimistic locking detects that the counter has already changed. The service reloads it and retries generation with the next number.

Data cleanup

Obsolete carts and redirects are removed through Symfony Console commands. The processes use DBAL to work in batches, locks to prevent concurrent runs, and maximum runtimes to limit database impact.

Monitoring and operations

Logs, alerts, and email summaries make each execution traceable. A Sonata interface exposes counter usage, while a dedicated command prepares references for a new period or initializes them for a new store.

Testing and tooling

PHPUnit covers reference generation, concurrent creation, and redirect cleanup, among other cases. Data-generation commands also support high-volume acceptance testing outside production.