{"id":47688331,"url":"https://github.com/marc-gavanier/ihexa","last_synced_at":"2026-05-09T02:20:44.619Z","repository":{"id":317983803,"uuid":"1068166335","full_name":"marc-gavanier/ihexa","owner":"marc-gavanier","description":"My personal take on the IHexa training: same learning path, different stack and architecture choices","archived":false,"fork":false,"pushed_at":"2026-04-26T23:06:45.000Z","size":1447,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-26T23:23:50.368Z","etag":null,"topics":["clean-architecture","feature-based","ihexa","nextjs","react","training"],"latest_commit_sha":null,"homepage":"https://d1064c2ochypva.cloudfront.net","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/marc-gavanier.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-10-02T00:36:42.000Z","updated_at":"2026-04-26T23:06:46.000Z","dependencies_parsed_at":"2025-10-04T10:25:19.859Z","dependency_job_id":"7b3af5b5-9c76-4337-8d10-685dd13f0f81","html_url":"https://github.com/marc-gavanier/ihexa","commit_stats":null,"previous_names":["marc-gavanier/ihexa"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/marc-gavanier/ihexa","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc-gavanier%2Fihexa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc-gavanier%2Fihexa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc-gavanier%2Fihexa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc-gavanier%2Fihexa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/marc-gavanier","download_url":"https://codeload.github.com/marc-gavanier/ihexa/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/marc-gavanier%2Fihexa/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32318417,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"ssl_error","status_checked_at":"2026-04-26T23:26:25.802Z","response_time":129,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clean-architecture","feature-based","ihexa","nextjs","react","training"],"created_at":"2026-04-02T15:07:07.226Z","updated_at":"2026-04-27T01:01:24.743Z","avatar_url":"https://github.com/marc-gavanier.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# My IHexa Training Progress\n\n[![Next.js](https://img.shields.io/badge/Next.js-16-black?logo=next.js)](https://nextjs.org/)\n[![React](https://img.shields.io/badge/React-19-61DAFB?logo=react\u0026logoColor=white)](https://react.dev/)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.9-3178C6?logo=typescript\u0026logoColor=white)](https://www.typescriptlang.org/)\n[![TailwindCSS](https://img.shields.io/badge/TailwindCSS-4-06B6D4?logo=tailwindcss\u0026logoColor=white)](https://tailwindcss.com/)\n[![DaisyUI](https://img.shields.io/badge/DaisyUI-5-5A0EF8?logo=daisyui\u0026logoColor=white)](https://daisyui.com/)\n[![Effect](https://img.shields.io/badge/Effect-3-black)](https://effect.website/)\n\n[![Playwright](https://img.shields.io/badge/Playwright-E2E-2EAD33?logo=playwright\u0026logoColor=white)](https://playwright.dev/)\n[![Vitest](https://img.shields.io/badge/Vitest-Unit-6E9F18?logo=vitest\u0026logoColor=white)](https://vitest.dev/)\n[![Cucumber](https://img.shields.io/badge/Cucumber-BDD-23D96C?logo=cucumber\u0026logoColor=white)](https://cucumber.io/)\n[![Storybook](https://img.shields.io/badge/Storybook-10-FF4785?logo=storybook\u0026logoColor=white)](https://storybook.js.org/)\n\n[![SST](https://img.shields.io/badge/SST-Serverless-E27152)](https://sst.dev/)\n[![AWS](https://img.shields.io/badge/AWS-Deploy-FF9900?logo=amazonwebservices\u0026logoColor=white)](https://aws.amazon.com/)\n[![pnpm](https://img.shields.io/badge/pnpm-Package_Manager-F69220?logo=pnpm\u0026logoColor=white)](https://pnpm.io/)\n\n\u003ch2 id=\"about\"\u003e🪧 About\u003c/h2\u003e\n\nThis repository contains my progress on the [**IHexa** training](https://www.ihexa.fr/), with a twist: I adapt the suggested path to my own technological choices and code organization.  \nThe goal is to provide an alternative example, staying faithful to the training while offering a different perspective that might interest others who have followed it.\n\nHere are some of my choices:\n- **Front-end**: Vue.js → React\n- **Backend**: Java API based → Next.js Server Components + Server Actions\n- **E2E tests tool**: Cypress → Playwright\n- **Versioning \u0026 repo**: GitLab → GitHub\n- **Code organization**: Hexagonal architecture “primary/secondary” → Feature-based Vertical Slices with colocated Abilities (Screaming Architecture principles)\n- **Domain modeling**: plain objects → functional domain model\n- **Project setup**: JHipster → tools official documentations (Sorry Colin! 😉)\n- **Database hosting**: Clever Cloud PostgreSQL → Neon (serverless PostgreSQL, scale-to-zero, branch-per-environment)\n- **ORM \u0026 migrations**: JPA + Liquibase → Drizzle ORM + Drizzle Kit migrations\n- **Integration testing strategy**: separate integration tests for repositories + Gherkin component tests simulating full API calls → Cucumber scenarios serve dual purpose: BDD acceptance tests (in-memory) and integration tests against PostgreSQL in CI\n- **Deployment**: Clever Cloud → AWS with SST (Serverless Stack) for Next.js applications with OpenNext\n- **UI Documentation**: tikui → Storybook\n- **UI Pattern library**: tikui → DaisyUI + TailwindCSS\n\nThis approach keeps me close to the training while exploring practical alternatives with others technologies.\n\n## 📑 Table of Contents\n\n- 🪧 [About](#about)\n- ✨ [My Approach \u0026 Choices](#approach)\n- 🤗 [Contributing](#contributing)\n- 📝 [License](#license)\n\n\u003ch2 id=\"approach\"\u003e✨ My Approach \u0026 Choices\u003c/h2\u003e\n\nHere is a more detailed explanation of the choices I made while following the IHexa training:\n- **React instead of Vue.js**: React is the most widely used tool for building web interfaces. However, it is also heavily influenced by practices that, in my opinion, can diverge from a clean architecture. I see this project as an opportunity to experiment with **alternatives that work without relying on the usual “messy” patterns** commonly found in React projects.\n- **Next.js instead of a Java-based backend**: similar to React, Next.js is becoming a widely adopted framework. However, most examples and tutorials rarely consider architectural concerns that emphasize a **domain isolated from the framework**. Using it here is an opportunity to **explore how a clean, domain-driven structure can coexist with a modern full-stack framework** that mixes client and server boundaries.\n- **Playwright instead of Cypress**: I’m familiar with Cypress, but I’ve never used Playwright. This is a great opportunity to **discover a new tool** and compare approaches for end-to-end testing.\n- **GitHub instead of GitLab**: purely for the pleasure of doing things differently and exploring an **alternative setup for CI/CD pipelines**. This allows me to compare approaches.\n- **Feature / Use Case-based organization**: this is a personal preference that makes navigating the code much easier. While I fully understand hexagonal architecture and its primary/secondary ports, translating the concept directly into folders often confuses me. I’m excessively sensitive to folder organization, so **this structure keeps the code readable and maintainable for me**.\n- **Functional domain modeling**: I usually model the domain in a functional style, but for this project I wanted to **go one step further** by learning how to use the **Effect** library and building a **purely functional domain model**. This allows encoding business rules in the type system and handling errors in a composable, effectful way rather than relying on runtime `throw`s.\n- **No JHipster**: I have a habit of **enjoying setups that are *slightly inconvenient***, forcing me to spend an unreasonable amount of time reading documentation and getting frustrated when things don’t work.\n- **Neon instead of Clever Cloud PostgreSQL**: Neon offers **serverless PostgreSQL with true scale-to-zero**, meaning the database costs nothing when idle, perfect for a learning project. Its **branch-per-environment** feature creates an isolated database copy in under a second for each ephemeral deployment, which is far more practical than provisioning a full Clever Cloud add-on per preview environment.\n- **Drizzle ORM instead of JPA + Liquibase**: Drizzle is a **lightweight, type-safe SQL toolkit** that fits naturally in a TypeScript codebase. Combined with Drizzle Kit for migrations, it provides a **code-first schema approach** where table definitions reference domain constants (e.g., max lengths), keeping the database schema aligned with business rules by design.\n- **Cucumber scenarios as integration tests**: in the training, **integration tests for repositories** and Gherkin-based component tests that simulate full API calls are separated. Since this project has **no standalone backend API** (Next.js server actions call domain logic directly), I chose to **reuse the same Cucumber scenarios** for both purposes: they run against in-memory implementations locally, and against a real PostgreSQL database in CI by simply switching the implementation profile (`ENV=prod`). This avoids duplicating test logic while still validating real database interactions.\n- **AWS with SST instead of Clever Cloud**: I’ve been wanting to try **SST (Serverless Stack)** for a while, as it is an **open alternative to Vercel**, offering similar simplicity while keeping full control over the infrastructure. Using it for this project was the perfect occasion to **experiment with modern serverless deployment**.\n- **DaisyUI + TailwindCSS instead of tikui**: DaisyUI provides a **solid design foundation** out of the box while staying **fully compatible with Tailwind’s utility-first approach**. Combined with TailwindCSS, it strikes a balance between having **ready-to-use components** and keeping enough **flexibility to customize the design** without the complexity often seen in pure Tailwind setups.\n- **Storybook instead of tikui documentation**: I’ve already used Storybook, but I wanted to go deeper into what the tool really offers: exploring its full potential for **interactive documentation**, **visual testing** and **design system workflows** for UI components.\n- **Near-zero infrastructure cost**: combined, AWS (Lambda, CloudFront, S3) and Neon both **scale to zero when idle**, less than 1€/year for a learning project with no traffic, a few euros per month for a low-traffic app, and still under 15€/month for a small production app with hundreds of daily users.\n\n\u003ch2 id=\"contributing\"\u003e🤗 Contributing\u003c/h2\u003e\n\nThis repository is primarily a personal progress log.  \nIf you want to share ideas, suggestions, or adaptations on this alternative version, feel free to open an **issue** or **pull request**.\n\nSee the [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions, available scripts, and environment configuration.\n\n\u003ch2 id=\"license\"\u003e📝 License\u003c/h2\u003e\n\nThis repository is for personal use and inspired by the [IHexa training](https://www.ihexa.fr/).\nSee the [LICENSE.md](./LICENSE.md) file in the repository for more information\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarc-gavanier%2Fihexa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarc-gavanier%2Fihexa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarc-gavanier%2Fihexa/lists"}