# About this Repository This repository hosts multiple implementations of the same back-end application. The aim is to provide quick, side-by-side comparisons of different technologies (languages, frameworks, libraries) while preserving consistent business logic across all implementations. Following principles such as **SOLID** and maintainable architectural patterns (**Clean, Hexagonal, Onion, or even DDD**) is recommended to clearly showcase the strengths and idioms of each technology. Some over-engineering is acceptable to demonstrate architectural features, but please keep implementations readable and avoid excessive complexity (e.g., skip event sourcing or atomic transactions unless intentionally focusing on those patterns for comparison). --- ### Project Idea: AutoStore A system to store items with expiration dates. When items expire, new ones are automatically ordered by making a POST request to the configured order URL. #### Business Rules (Domain) 1. **Each item has a name and an expiration date.** 2. **Expired items are automatically removed from the store.** 3. **When an item expires, a new item of the same type is automatically ordered.** 4. **Expired items can be added to the store, triggering immediate ordering.** 5. **Every item belongs to a user.** 6. **Only the item's owner can manage it.** #### Application Requirements 1. **Users can log in to obtain a JWT.** 2. **Authenticated users manage their personal collection of items via an HTTP API.** 3. **Each item has an associated "order URL".** 4. **When an item expires, the system must notify the "order URL" with an HTTP POST request.** 5. **This call should occur immediately when the item's expiration date is reached, or when an expired item is added.** 6. **Upon startup, the system must verify expiration dates for all items.** 7. **Persistent storage must be used (file, database, etc.).** **Note:** For simplicity, user CRUD is skipped. Integrate with an OP (OpenID Provider) service like Keycloak, Authentic, or Zitadel, or mock authentication with a simple Docker service. Alternatively, simply authenticate a predefined user and return a JWT on login. --- ## Layer Boundaries | Layer | Responsibility | Internal Dependencies | External Dependencies | |-------------------|--------------------------------------------------------------- |-----------------------|-----------------------| | **Domain** | Entities, value objects, domain services (pure business logic) | None | None (language only) | | **Application** | Use cases, orchestration, DTOs, infrastructure interfaces | Domain | None or minimal | | **Infrastructure**| Implementations (repositories, HTTP, auth), background jobs | Application | Any (framework/lib) | | **Presentation** | API controllers, DTOs, auth middleware | Application | UI/web/CLI/others | | **Assembly** | Main app, DI, startup logic, job scheduling | Any layer | DI container, config, framework, etc.| --- ### Possible directory layout (will vary from tech to tech) ```plaintext AutoStore/ ├── App # app assembly │ ├── Main │ ├── AppConfig │ └── ... ├── Extern │ ├── │ └── <...downloaded libraries and git submodules> ├── Src # internal/lib/src │ ├── Domain/ │ │ ├── Entities/ │ │ │ ├── User │ │ │ └── Item │ │ └── Specifications/ │ │ └── ItemExpirationSpec # domain knowledge (from domain experts) │ ├── Application/ │ │ ├── Commands/ # use cases │ │ │ ├── Login │ │ │ ├── AddItem │ │ │ ├── DeleteItem │ │ │ └── HandleExpiredItems │ │ ├── Queries/ # use cases (read only) │ │ │ ├── GetItem │ │ │ └── ListItems │ │ ├── Interfaces/ │ │ │ ├── IUserRepository │ │ │ ├── IItemRepository │ │ │ ├── IAuthService │ │ │ └── IDateProvider │ │ ├── Dto/ # data transfer objects (fields mappings, validation, etc.) │ │ └── Services/ │ │ ├── UserInitializationService │ │ └── ExpirationScheduler │ ├── Infrastructure/ │ │ ├── Repositories/ │ │ │ ├── FileUserRepository │ │ │ └── FileItemRepository │ │ ├── Adapters/ │ │ │ ├── JwtAuthAdapter │ │ │ ├── OrderUrlHttpClient │ │ │ ├── SystemDateProvider │ │ │ └── <... some extern lib adapters> │ │ └── Helpers/ │ │ └── <... DRY helpers> │ ├── Cli # presentation, optional command line use case caller │ └── WebApi/ # presentation, REST (controllers, middlewares, etc.) │ ├── Controllers/ │ │ ├── StoreController │ │ └── UserController │ └── Auth/ │ └── JwtMiddleware └── Tests ├── Unit/ └── Integration/ ``` --- ## Domain Knowledge and Repository Queries Business rules like expiration checks (`expirationDate <= currentDate`) represent domain knowledge that **must have a single source of truth**. This logic might evolve (e.g., to `<= currentDate - N days` or vary by item type) and should never be duplicated across the codebase. While simple predicates (like `findWhere(predicate(Item))`) work for in-memory repositories, SQL-based repositories need to translate these rules into efficient WHERE clauses. One solution (not too over-engineered) would be to pass DTO or value object ready to be put into queries (e.g., `fetchExpiredItems(calculatedConditionFields)`). But for fun and possible UI search, consider implementing a specification pattern with a simple condition abstraction that exposes the business rule as composable conditions (field, operator, value). This allows domain services to define rules once, use cases to apply them consistently, and repositories to translate them into optimal queries by interpreting the conditions according to their storage mechanism. Avoid duplicating the business logic in repository implementations - instead, let repositories consume the specification and build their queries accordingly. This aims to overcome to-repo-and-back drawbacks depicted in *Evans, Eric (2003). Domain Driven Design. Final Manuscript*. --- ## Build and Run Each implementation should include a `/docker/docker-compose.yml` file so that you can simply run: ```bash cd docker && docker compose up --build ``` to build, test and run the application. Otherwise, please provide a `/README.md` file with setup and running instructions. ## API Endpoints See `openapi.yaml` file for suggested API (test it with Tavern, Postman etc.). Here's a summary of example API endpoints: | Endpoint | Method | Description | |-------------------------|--------|--------------------------------------| | `/login` | POST | Authenticate user and get JWT token | | `/items` | GET | Get user's items | | `/items` | POST | Create new item | | `/items/{id}` | GET | Get item by ID | | `/items/{id}` | PUT | Update item details | | `/items/{id}` | DELETE | Delete item | Suggested base URL is `http://localhost:50080/api/v1/`. ## Testing - Each implementation should include its own **unit tests** and **integration tests**, which must run automatically during the Docker image build. - Implementation-independent functional tests are provided in `testing/tavern/` - Tavern API tests (requests and assertions) must pass for every implementation to ensure consistent behavior across all technology stacks. - For debugging and verifying the automatic ordering feature, use the helper service in `testing/http-echo-server/` which provides a simple Docker Compose setup that listens on port 8888 and logs all incoming POST requests, allowing you to observe when expired items trigger order notifications.