{"id":40399912,"url":"https://github.com/eiberham/superchef","last_synced_at":"2026-05-26T12:44:21.259Z","repository":{"id":328414132,"uuid":"1111388135","full_name":"eiberham/superchef","owner":"eiberham","description":":hamburger: AI-powered chef assistant that improves your recipes using your own data built with NestJS","archived":false,"fork":false,"pushed_at":"2026-02-07T21:16:12.000Z","size":1736,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-08T05:48:26.768Z","etag":null,"topics":["honeycomb","kafka","langchain","langchain-typescript","llms","nestjs","opentelemetry","postgresql","prisma-orm","rabbitmq","rbac","stripe"],"latest_commit_sha":null,"homepage":"","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/eiberham.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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-12-06T20:51:16.000Z","updated_at":"2026-02-07T21:16:16.000Z","dependencies_parsed_at":"2025-12-28T12:00:38.568Z","dependency_job_id":null,"html_url":"https://github.com/eiberham/superchef","commit_stats":null,"previous_names":["eiberham/recipebooster","eiberham/superchef"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/eiberham/superchef","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiberham%2Fsuperchef","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiberham%2Fsuperchef/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiberham%2Fsuperchef/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiberham%2Fsuperchef/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eiberham","download_url":"https://codeload.github.com/eiberham/superchef/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eiberham%2Fsuperchef/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33521330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"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":["honeycomb","kafka","langchain","langchain-typescript","llms","nestjs","opentelemetry","postgresql","prisma-orm","rabbitmq","rbac","stripe"],"created_at":"2026-01-20T13:31:42.390Z","updated_at":"2026-05-26T12:44:21.253Z","avatar_url":"https://github.com/eiberham.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Table of Contents\n\n1. [Introduction](#superchef)\n2. [Routes](#routes)\n3. [Authentication \u0026 Security](#authentication--security)\n   - [JWT-based Authentication](#jwt-based-authentication)\n   - [Role-Based Access Control (RBAC)](#role-based-access-control-rbac)\n   - [Route Protection](#route-protection)\n   - [Rate Limiting](#rate-limiting)\n4. [Observability \u0026 Distributed Tracing](#observability--distributed-tracing)\n5. [Async Processing with RabbitMQ](#async-processing-with-rabbitmq)\n   - [Event-driven Architecture](#event-driven-architecture)\n   - [Producers \u0026 Consumers Separation](#producers--consumers-separation)\n6. [Caching (Redis)](#caching-redis)\n7. [User Preferences](#user-preferences)\n8. [AI Recipe Assistant](#ai-recipe-assistant)\n9. [Analytics](#bar_chart-analytics)\n10. [Database Transactional Outbox Pattern](#outbox_tray-database-transactional-outbox-pattern)\n11. [Database Scaling](#oil_drum-database-scaling)\n12. [Automated Testing \u0026 CI](#test_tube-automated-testing--ci)\n13. [Project setup](#project-setup)\n14. [Environment variables](#environment-variables)\n15. [Compile and run the project](#compile-and-run-the-project)\n16. [Run tests](#run-tests)\n17. [Deployment](#deployment)\n18. [License](#license)\n\n\n## SuperChef\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./superchef.jpg\" alt=\"superchef\" /\u003e\n\u003c/p\u003e\n\n\u003ctable border=\"0\" cellspacing=\"0\" cellpadding=\"0\" style=\"border-collapse: collapse; border: none;\"\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg alt=\"GitHub\" src=\"https://img.shields.io/github/license/eiberham/superchef?style=for-the-badge\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg alt=\"GitHub code size in bytes\" src=\"https://img.shields.io/github/languages/code-size/eiberham/superchef?style=for-the-badge\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg alt=\"GitHub top language\" src=\"https://img.shields.io/github/languages/top/eiberham/superchef?style=for-the-badge\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg alt=\"GitHub last commit\" src=\"https://img.shields.io/github/last-commit/eiberham/superchef?style=for-the-badge\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg alt=\"GitHub stars\" src=\"https://img.shields.io/github/stars/eiberham/superchef?style=for-the-badge\"\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cimg alt=\"GitHub workflow status\" src=\"https://img.shields.io/github/actions/workflow/status/eiberham/superchef/ci.yml?style=for-the-badge\"\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nSuperChef is an AI-powered chef assistant designed to analyze existing recipes, suggest meaninful improvements, and help you create better dishes using your current ingredients.\n\nIt works on top of your current database, providing practical, cooking-focused recommendations rather than generic advice.\n\nTLDR features:\n\n- Real world backend concerns\n- Async workflows\n- Security best practices\n- Clean NestJS architecture\n- Pragmatic use of message queue\n\n## :electric_plug: Routes\n\nAll API endpoints are documented using **Swagger (OpenAPI)**.\n\nOnce the application is running, the interactive API documentation is available at:\n\n- `GET /apis`\n\nThe Swagger UI provides request/resoponse schemas, parameters, and example payloads for each endpoint.\n\nBelow is a high level overview of the available routes:\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eVerb\u003c/th\u003e\u003cth\u003eResource\u003c/th\u003e\u003cth\u003eDescription\u003c/th\u003e\u003cth\u003eScope\u003c/th\u003e\u003cth\u003eRole Access\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePOST\u003c/td\u003e\u003ctd\u003e/auth/login\u003c/td\u003e\u003ctd\u003eSuperchef sign in\u003c/td\u003e\u003ctd\u003ePublic\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePOST\u003c/td\u003e\u003ctd\u003e/auth/refresh\u003c/td\u003e\u003ctd\u003eToken refresh\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePOST\u003c/td\u003e\u003ctd\u003e/auth/logout\u003c/td\u003e\u003ctd\u003eSign out\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eGET\u003c/td\u003e\u003ctd\u003e/ingredients\u003c/td\u003e\u003ctd\u003eGet ingredients list\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eGET\u003c/td\u003e\u003ctd\u003e/ingredients/:id\u003c/td\u003e\u003ctd\u003eGet a single ingredient\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePOST\u003c/td\u003e\u003ctd\u003e/ingredients\u003c/td\u003e\u003ctd\u003eCreate an ingredient\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePUT\u003c/td\u003e\u003ctd\u003e/ingredients/:id\u003c/td\u003e\u003ctd\u003eUpdate an ingredient\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eDELETE\u003c/td\u003e\u003ctd\u003e/ingredients/:id\u003c/td\u003e\u003ctd\u003eDelete ingredient\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eGET\u003c/td\u003e\u003ctd\u003e/recipes\u003c/td\u003e\u003ctd\u003eGet the recipes list\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eGET\u003c/td\u003e\u003ctd\u003e/recipes/:id\u003c/td\u003e\u003ctd\u003eGet a single recipe\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePOST\u003c/td\u003e\u003ctd\u003e/recipes\u003c/td\u003e\u003ctd\u003eCreate a recipe\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePUT\u003c/td\u003e\u003ctd\u003e/recipes/:id\u003c/td\u003e\u003ctd\u003eUpdate a recipe\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eDELETE\u003c/td\u003e\u003ctd\u003e/recipes/:id\u003c/td\u003e\u003ctd\u003eDelete a recipe\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eGET\u003c/td\u003e\u003ctd\u003e/users\u003c/td\u003e\u003ctd\u003eGet users list\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eGET\u003c/td\u003e\u003ctd\u003e/users/:id\u003c/td\u003e\u003ctd\u003eGet a single user\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePOST\u003c/td\u003e\u003ctd\u003e/users\u003c/td\u003e\u003ctd\u003eCreate a user\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePUT\u003c/td\u003e\u003ctd\u003e/users/:id\u003c/td\u003e\u003ctd\u003eUpdate a user\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eDELETE\u003c/td\u003e\u003ctd\u003e/users/:id\u003c/td\u003e\u003ctd\u003eDelete a user\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003ePOST\u003c/td\u003e\u003ctd\u003e/chat\u003c/td\u003e\u003ctd\u003eSends a message to the superchef agent\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eGET\u003c/td\u003e\u003ctd\u003e/analytics/top-recipes\u003c/td\u003e\u003ctd\u003eGet the top ten most improved recipes\u003c/td\u003e\u003ctd\u003eProtected\u003c/td\u003e\u003ctd\u003eAdmin, Viewer\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n## :shield: Authentication \u0026 Security\n\n#### JWT-based Authentication\n\n- Stateless authentication using JWT access tokens\n- Tokens are issued on login and required for protected routes\n- Designed to be compatible with API clients and frontends.\n- Refresh tokens, enabling token rotation and secure session renewal without re-authentication.\n\n#### Role-Based Access Control (RBAC)\n\n- Users can have one or more roles\n- Example roles:\n  - admin\n  - viewer\n\nRBAC is applied at the route level, ensuring fine grained authorization.\n\n#### Route Protection\n\n- Global authentication guard ensures all protected routes require a valid JWT.\n- Public routes are explicitly marked.\n- Authorization logic is separated from controllers.\n\n#### Rate Limiting\n\n- Built-in rate limiter to protect the API from abuse.\n- Prevents excessive requests to sensitive endpoints\n- Configurable limits per route or globally.\n\n## :flashlight: Observability \u0026 Distributed Tracing\n\nThis project implements a high-level observability pattern using [OpenTelemetry](https://opentelemetry.io/) and [Honeycomb](https://www.honeycomb.io/). Instead of traditional isolated logs, we use Distributed Tracing to correlate every log entry with a specific request flow.\n\n#### Key Features\n- **Log Correlation:** Every log entry is automatically enriched with a traceId and spanId, allowing for end-to-end debugging.\n\n- **Span Events:** Application logs are pushed to Honeycomb as \"Span Events,\" providing a millisecond-accurate timeline of events within a request.\n\n- **Automatic Context Propagation:** Tracing context is maintained across asynchronous boundaries and distributed systems (e.g., RabbitMQ).\n\n- **Custom Telemetry Logger:** A specialized Logger extends the NestJS ConsoleLogger to handle tracing logic without polluting the Business Logic.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./telemetry.png\" alt=\"superchef\" /\u003e\n\u003c/p\u003e\n\n#### How to use\n\nThe system is designed to be transparent for developers. Simply use the standard NestJS Logger service:\n\n```typescript\nprivate readonly logger = new Logger(AuthService.name);\n\nasync handle() {\n  this.logger.log('User logged in'); // Automatically appears in Honeycomb's trace timeline\n}\n```\n\n#### Monitoring Dashboard\n\nTraces, errors, and performance metrics are available in Honeycomb. Search by traceId to see the full \"waterfall\" view of any operation.\n\n## :rabbit2: Async Processing with RabbitMQ\n\n#### Event-driven Architecture\n\n- RabbitMQ is used to handle async workflows\n- Examples:\n  - User registration triggers a welcome email\n  - Extensible to notifications\n\n#### Producers \u0026 Consumers Separation\n\n- API publishes domain events\n- Workers consume and process them independently\n- Designed to be monolith-friendly, without premature microservices.\n\n## :brain: Caching (Redis)\n\nSuperchef uses [Redis](https://redis.io/) as an in-memory cache to reduce latency and decrease load on the primary database.\n\nThe cache is applied to read-heavy endpoints, which keeps [PostgreSQL](https://www.postgresql.org/) as the single source of thruth while improving response times for frequent reads.\n\n## :gear: User Preferences\n\nEach user can configure dietary preferences that are stored as JSON object inside the user table.\nSuported fields:\n- `diet`: \"none\" | \"vegetarian\" | \"vegan\" | \"omnivore\"\n- `alergies`: string[]\n\n## :robot: AI Recipe Assistant\n\nSuperchef includes an AI-powered assistant via the `/chat` endpoint, that helps users improve existing recipes by suggesting variations, optimizations, or substitutions based on natural language prompts.\n\nThe assistant is implemented as a backend agent powered by OpenAI and orchestrated server side.\n\nAll suggestions are generated in the context of a real recipe stored in the database.\n\n## :bar_chart: Analytics\n\nThis module handles the processing and delivery of recipe popularity metrics using a decoupled, event-driven architecture. By offloading analytics from the main API, we ensure high performance and system resilience.\n\n#### Architecture Overview\n\nThe system implements separation of concerns by decoupling read and write operations through an event bus:\n\n1. **Ingestion:** Every time a recipe is improved through the ai agent, a `recipe.improvement` event is published to kafka.\n2. **Processing:** The analytics microservice reads this event and performs an atomic increment in redis.\n3. **Consumption:** The api retrieves the ranking by talking to the analytics microservice through a rpc-like request, fetching the pre-aggregated data from redis.\n\nFor better understanding you can find the detailed process in the imagen below:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./analytics.png\" alt=\"superchef\" /\u003e\n\u003c/p\u003e\n\n#### Specification\n\nGET `/analytics/top-recipes`\n\n- Retrieves the top ten most improved recipes.\n\nSample response:\n\n```json\n[\n  { \"id\": \"uuid-101\", \"name\": \"Classic Lasagna\", \"count\": 245 },\n  { \"id\": \"uuid-202\", \"name\": \"Spicy Ramen\", \"count\": 189 }\n]\n```\n\n## :outbox_tray: Database Transactional Outbox Pattern\n\nWhen a user is created in the system two things happen:\n\n1. A new record is created in the users table respectively.\n2. A welcome email is dispatched to the user's inbox.\n\nThis alone, could be a problem and lead to data inconsistencies, for example, it could be the case that the user is created successfully in our database but the message broker for whatever reason goes down precisely at that moment and the message is not delivered.\n\nHow do we mitigate this ?\n\nBy adding a transactional outbox pattern, this is how it works:\n\n1. There's a table holding the outbox events:\n\n  ```typescript\n  model OutboxEvent {\n    id          String   @id @default(uuid())\n    topic       String\n    payload     Json\n    status      OutboxStatus @default(PENDING)\n    error       String?\n    attempts    Int      @default(0)\n    createdAt   DateTime @default(now()) @map(\"created_at\")\n    updatedAt   DateTime @default(now()) @map(\"updated_at\")\n\n    @@index([status, createdAt])\n    @@map(\"outbox_event\")\n  }\n  ```\n\n  Creating the user is done by means of a transaction, this transaction involves updating both the user table and the outbox_event table.\n\n2. There's a cron job checking the outbox_event table every `5` seconds. \n\n- If there's a `PENDING` event it will try to send it to the message broker so it can be processed. \n- If the processing fails and the third attempt hasn't been reached the status remains `PENDING` and the attempts count bumps up.\n- If it's the third attempt and the processing fails the status is updated to `FAILED`.\n\nYou can check the entire flow in the image below.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./outbox.png\" alt=\"superchef\" /\u003e\n\u003c/p\u003e\n\n## :oil_drum: Database Scaling\n\nAs a first measure to horizontally scale the persistence layer two instances of the PostgreSQL database are present, the primary node and the replica. Separating the reading conexions from the writting ones.\n\nThis was easy to implement with Prisma through the extension `extension-read-replicas`\n\n## :test_tube: Automated Testing \u0026 CI\n\nThe project implements automated robust E2E tests using [Jest](https://jestjs.io/) and [Prisma](https://www.prisma.io/).\n\nTo avoid affecting the real database the CI/CD pipeline in Github orchestrates a real-time testing environment using Docker Service Containers:\n\n- Every PR triggers a workflow that spins up a dedicated Postgres 15 container.\n- The pipeline automatically handles Prisma migrations and database seeding before executing tests.\n- Implements pg_isready checks to ensure database availability before the test suite starts, preventing race conditions.\n\n## :credit_card: Stripe Integration\n\nSuperchef integrates with Stripe for subscription management, allowing users to subscribe to a basic plan and access enhanced features.\n\n#### Features\n\n- Checkout Session Creation: Create Stripe Checkout sessions for subscription purchases\n- Webhook Processing: Handle Stripe webhook events (checkout.session.completed)\n- Subscription Management: Automatically update subscription status and billing periods\n- Customer Management: Create and manage Stripe customers linked to user accounts\n\n#### Supported Webhook Events\n\n| Event                           | Description                     | Action                                                       |\n| ------------------------------- | ------------------------------- | ------------------------------------------------------------ |\n| `checkout.session.completed`    | Checkout completed successfully | Updates subscription status, billing period, and user access |\n| ------------------------------- | ------------------------------- | ------------------------------------------------------------ |\n| `customer.subscription.deleted` | Customer unsubscribed.          | Updates subscription status, billing period, and user access |\n| ------------------------------- | ------------------------------- | ------------------------------------------------------------ |\n| `invoice.paid`                  | Invoice paid successfully.      | Updates subscription status, billing period, and user access |\n| ------------------------------- | ------------------------------- | ------------------------------------------------------------ |\n| `invoice.payment.failed`.       | Invoice Payment Failed          | Updates subscription status, and notifies the user.          |\n\n## Project setup\n\n```bash\n$ npm install\n```\n\n## :closed_lock_with_key: Environment variables\n\nCreate a `.env` file in the root of your project and add the following env vars:\n\n```bash\nDATABASE_URL=\nOPENAI_API_KEY=\nRESEND_API_KEY=\nJWT_SECRET=\nLOG_LEVEL=[\"log\", \"error\", \"warn\", \"debug\", \"verbose\"]\nREDIS_HOST=\nREDIS_PORT=\nREDIS_USERNAME=\nREDIS_PASSWORD=\nSTRIPE_API_KEY=\nHONEYCOMB_API_KEY=\n```\n\n## Compile and run the project\n\n```bash\n# development\n$ npm run start\n\n# watch mode\n$ npm run start:dev\n\n# production mode\n$ npm run start:prod\n```\n\n## Run tests\n\n```bash\n# unit tests\n$ npm run test\n```\n\n## Deployment\n\nWhen you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.\n\nIf you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:\n\n```bash\n$ npm install -g @nestjs/mau\n$ mau deploy\n```\n\nWith Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.\n\n### License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feiberham%2Fsuperchef","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feiberham%2Fsuperchef","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feiberham%2Fsuperchef/lists"}