Skip to main content

Project Reflection: From Idea to an AI-Supported Christmas Market Platform

Emil Dagsberg
Author
Emil Dagsberg
Computer science student documenting the jump from beginner to builder.

Introduction
#

In my earlier blog posts, I first described the idea behind the project and then how it started taking shape as a real application. Now that the project has progressed further, it makes sense to gather the threads and reflect more fully on what we have actually built, why we built it, where AI adds value, and what I have learned along the way.

The project is based on E.G. and their Christmas market. The concrete challenge was that much of the work around standholders seemed manual, person-dependent, and reliant on emails, mental overview, and previous experience. That made the case relevant because there was a clear problem to work on, but also because it was a good example of an area where AI should not replace people, but support an existing workflow.

An important part of the project has not only been the solution itself, but also the way I have worked. I have used Codex extensively as a coding agent during the process, and that has had a strong impact on how I structured tasks, documented decisions, and moved between idea, specification, implementation, and testing.

What Have We Built?
#

In short, we built a digital solution that brings several parts of the standholder workflow together in one system.

In practice, the solution consists of:

  • A public React frontend that resembles the existing Christmas market site
  • A digital application form for new standholders
  • An Express backend that receives, validates, and stores applications
  • AI-supported categorization of new applications
  • Mail flows for submitted applications and outreach to previous standholders
  • A public standholder list built around locations, search, and filtering

The user is not just one person. There is both an internal user and an external user.

The internal user is the person at the client organization who needs to handle applications, maintain an overview of standholders, and send recurring communication. The external user is both the business applying to participate and the visitor who later needs to navigate the market and discover relevant standholders.

What Problem Does the Solution Solve?
#

The main value of the project is that data becomes structured from the beginning.

Instead of a business first having to send an email to request a form, and then having its information read, interpreted, and moved manually, the business can now submit its information directly through a digital form. That means the information is immediately ready for further use.

This creates value on several levels:

  • The client gets less manual work
  • It becomes easier to create an overview of incoming applications
  • Repeated communication can be standardized and partly automated
  • Data can be reused between internal administration and public display
  • Knowledge from previous years becomes easier to build on

If the solution were fully realized, the client would not just get a nicer form. They would get a more robust workflow where less depends on one person’s memory and manual coordination.

What Assumptions Did the Project Build On?
#

The project was based on a few fairly clear assumptions.

The first assumption was that the current standholder process really is manual enough that digitization would create real value. The second was that the same data can be reused in several parts of the system if it is collected properly the first time. The third was that AI makes the most sense as support for interpretation and suggestion, not as an autonomous decision-maker.

We also deliberately chose not to build certain things in order to keep the project realistic:

  • We did not build a full production-ready dashboard on our own
  • We did not finish a live map feature in this iteration
  • We did not build full spam protection and hardening
  • We did not build a fully automatic mail system without human oversight
  • We did not build a large visitor chatbot or GPS-like navigation

That was a conscious scope choice. Otherwise the project would have spread too wide.

Where Does AI Fit Into the Solution?
#

AI is mainly used for categorizing new applications and in the way we think about workflow support.

When a new business sends an application, the product description is often free text. That is exactly where AI makes sense, because the input is not fully clean or standardized. A model can help turn a messy description into something more structured, such as a broader category and a set of tags that can later be used in the system.

The input is typically:

  • Business information
  • Product description
  • Practical information from the form

The output is typically:

  • A suggested category
  • Relevant tags
  • A justification or structured classification that the system can build on

AI can do some useful things in this solution:

  • It can handle imprecise and varied descriptions better than hardcoded rules alone
  • It can save time in the first sorting step
  • It can help make data more consistent

But it can also fail:

  • It can place a business in a category that is too broad or simply wrong
  • It can be inconsistent across similar applications
  • It can sound convincing even when it is wrong

That is why human approval should still exist around the most important decisions. AI should suggest, not decide.

How Did I Work With AI, Structure, and Codex?
#

One of the most important things I have learned is that the AI part works best when the rest of the surrounding system is structured.

It is not only about calling a model. It is also about defining:

  • What context the model receives
  • What output format you want
  • What should happen if the model is unavailable
  • When a heuristic fallback is good enough

In our solution, we worked with model-based categorization, but also with fallback logic so the system does not break if the AI does not respond or returns a weak result. That was an important design decision, because it turns AI into an enhancement of the system rather than a single point of dependency.

I have also worked a lot with a more specification-driven way of developing during the project. Not as a heavy formal document every time, but as a way of working where I first try to clarify:

  • what the concrete feature should do
  • who it is for
  • which inputs and outputs exist
  • what is intentionally postponed

That applied both to the actual coding and to my use of Codex as a coding agent.

One of the most useful things in practice was that I created small markdown files with project status, priorities, handoff notes, and specs, which I could give back to Codex later. That meant I did not have to start completely from scratch every time, and it also meant I could work across devices. If I continued the work somewhere else, I could take the same .md files with me and give Codex the necessary context quickly.

An example of that kind of context could look like this:

# Current priorities

1. Make the vendor form fully operational
2. Build AI-powered standholder list
3. Automate outreach emails to last year's standholders

## Scope decisions
- Another group member is handling the dashboard
- Live map is optional for now
- Spam protection is intentionally deferred

## Important note
- AI should suggest categories, not make final decisions

That type of file worked for me as a bridge between my own understanding of the project and Codex’s working style. Instead of only writing new prompts each time, I could reuse documented project context.

My workflow with Codex therefore often looked like this:

  1. I described the goal or updated a markdown file with the current status
  2. Codex read the project context and inspected the code
  3. Codex suggested or implemented changes
  4. I tested the result locally
  5. I gave errors, logs, or new direction back
  6. We iterated from there

That was especially useful in a project like this, where frontend, backend, AI, emails, and data flows constantly affected each other.

Technical Solution and Architecture
#

The architecture ended up being more concrete and more pragmatic than my early reflections suggested.

The frontend is built in React, where we have public pages such as the Christmas market page, this year’s program, information for standholders, and the standholder list. The backend is built in Express and handles API calls, validation, mail flow, outreach logic, and AI calls. Data is stored in a PostgreSQL database in the newer version of the project, while seed data and a few demo-oriented flows still interact with JSON-based files where that made sense during the development phase.

The data flow looks like this in simplified form:

  1. A business fills out the form in the frontend
  2. The frontend sends the data to the backend
  3. The backend validates the input and tries to categorize the application
  4. The backend stores the application and links it to relevant business data
  5. The backend attempts to send mail through SMTP
  6. The structured data can later be used in administration and public display

We also worked with how previous data can be included in the solution. That especially applies to the standholder list and the outreach flow, where last year’s businesses can be used as realistic demo and working material.

A small example of the data flow in code is the frontend call to the backend when an application is submitted:

async function submitApplication(formData) {
  const response = await fetch("/api/applications", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(formData)
  });

  return response.json();
}

It is a small example in itself, but it illustrates the core point of the project well: data should not just be shown in a form, it should move forward into a flow where it is validated, categorized, stored, and reused.

Which Technical Choices Am I Most Satisfied With?
#

There are especially three choices I am satisfied with.

The first is that we did not only build a nice-looking frontend, but a real connected data-flow solution. The form is not just a mockup. It sends data into a system that actually does something with it.

The second is that AI is placed where it makes sense. We did not force AI into everything. We use it where the problem is genuinely about interpreting text and creating structure.

The third is that we treated data reuse as a central principle. The same data foundation can support applications, administration, outreach, and public display. That makes the solution stronger than if it were just another isolated form.

What Would I Change If I Built It Again?
#

If I were to build the project again from scratch, I would be even sharper about the data model and the division of responsibilities from the beginning.

Some of the project work showed that it is easy to come up with many connected ideas, but harder to make sure all flows fit together cleanly at a technical level, especially when several people work in parallel. I would therefore lock down earlier:

  • which data is the source of truth
  • how status changes should affect the rest of the system
  • where human approval should live
  • how the admin side and the public side should connect most elegantly

I would also plan earlier and more explicitly for robustness around mail, environment variables, and local development flows, because those practical integration points often take more time than expected.

My Own Contribution
#

My own contribution has mainly been in the parts where frontend, backend, AI, and mail flow meet.

I have especially worked on:

  • the public frontend and its structure
  • the standholder form and its flow
  • backend logic for receiving and processing applications
  • AI-supported categorization
  • the public standholder list
  • outreach emails to previous standholders
  • the practical use of Codex as part of the development process

Those are also the parts of the solution I feel I understand best, because I have worked with both the user experience, the data flow, and the technical integrations behind it.

I also think it is important to mention that Codex has not just been a tool for generating isolated code snippets. I used it more like a development partner. That meant I had to be clear about my goals, write better context, and think more explicitly about what should be built and what should not be built.

One important lesson for me has been that it is not enough to make something work in isolation. You also have to make it fit with the rest of the system and with the problem the client actually has.

What Have I Learned About Building AI-Driven Applications?
#

The most important lesson is that AI-driven applications are rarely mostly about the model itself.

The difficult and interesting part often lies in everything around the model:

  • when AI is actually relevant
  • how input should be structured
  • what should happen when errors occur
  • how output can be used safely
  • where human control should be placed

I have also learned that the quality of AI output is closely connected to the quality of the rest of the system. If the context is unclear, if the domain is not thought through, or if the output is not used in a well-designed way, then even a strong model is not enough on its own.

At the same time, the project has made it clear to me that coding agents like Codex can be very useful in a real development process, but only when they are used as a collaborator rather than a replacement for understanding. They work best in an iterative process with goals, testing, feedback, and adjustment.

That is probably one of the most important experiences I take away from the project: when I work well with Codex, it is not about writing as little as possible myself. It is about being good at describing the problem, keeping track of the context, and being able to judge whether the generated result actually fits the needs of the project.

Conclusion
#

If I had to point to the most important thing I learned from the process, it would probably be this: the best AI solution is not the most advanced one, but the one that fits best into a concrete workflow and makes a real problem easier to handle.

This project has been a good example of exactly that. We did not just try to build something with AI because AI is exciting. We tried to build a solution where structure, automation, and AI together can create value for a concrete client with a concrete need.

For me, the project has therefore been both an exercise in software development, product understanding, and critical use of AI. That is also what makes it one of the most educational projects in the course.