{"id":45627288,"url":"https://github.com/apolenkov/myapp-hello","last_synced_at":"2026-03-03T13:08:04.922Z","repository":{"id":339604862,"uuid":"1162632915","full_name":"apolenkov/myapp-hello","owner":"apolenkov","description":"Production-ready NestJS REST API with PostgreSQL, JWT auth, OpenTelemetry observability, and Docker Swarm deployment","archived":false,"fork":false,"pushed_at":"2026-02-27T18:56:45.000Z","size":305,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-27T20:33:22.227Z","etag":null,"topics":["docker","docker-swarm","grafana","jwt-authentication","nestjs","opentelemetry","postgresql","prometheus","rest-api","typescript"],"latest_commit_sha":null,"homepage":null,"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/apolenkov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2026-02-20T14:03:14.000Z","updated_at":"2026-02-27T18:50:59.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/apolenkov/myapp-hello","commit_stats":null,"previous_names":["apolenkov/myapp-hello"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/apolenkov/myapp-hello","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apolenkov%2Fmyapp-hello","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apolenkov%2Fmyapp-hello/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apolenkov%2Fmyapp-hello/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apolenkov%2Fmyapp-hello/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apolenkov","download_url":"https://codeload.github.com/apolenkov/myapp-hello/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apolenkov%2Fmyapp-hello/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29957128,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T22:53:01.873Z","status":"ssl_error","status_checked_at":"2026-02-28T22:52:50.699Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["docker","docker-swarm","grafana","jwt-authentication","nestjs","opentelemetry","postgresql","prometheus","rest-api","typescript"],"created_at":"2026-02-23T21:29:45.722Z","updated_at":"2026-03-01T01:04:12.237Z","avatar_url":"https://github.com/apolenkov.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# myapp-hello\n\n[![CI/CD](https://img.shields.io/github/actions/workflow/status/apolenkov/myapp-hello/ci.yml?branch=main\u0026label=CI%2FCD\u0026logo=github)](https://github.com/apolenkov/myapp-hello/actions)\n[![codecov](https://img.shields.io/codecov/c/github/apolenkov/myapp-hello?logo=codecov)](https://codecov.io/gh/apolenkov/myapp-hello)\n[![Node.js](https://img.shields.io/badge/node-%3E%3D22-brightgreen?logo=node.js)](https://nodejs.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n\nA production-ready Node.js REST API built with NestJS and PostgreSQL. Ships with structured logging,\nOpenTelemetry instrumentation, JWT authentication guard, rate limiting, OpenAPI documentation,\nautomated database migrations, a full CI/CD pipeline, and a complete observability stack (Grafana +\nPrometheus + Loki + Tempo) — all deploying to three isolated environments on a Docker Swarm VPS via\nDokploy.\n\n## Architecture\n\n\u003c!-- prettier-ignore --\u003e\n```mermaid\n%%{init: {theme: 'neutral'}}%%\nflowchart TD\n    dev[Developer] --\u003e|git push| github[GitHub]\n    user[End User] --\u003e|HTTPS| traefik[Traefik v3\\nReverse Proxy]\n\n    github --\u003e|GitHub Actions CI/CD| dokploy[Dokploy\\nPaaS API]\n    dokploy --\u003e|Docker Swarm deploy| swarm\n\n    subgraph swarm[VPS 185.239.48.55 — Docker Swarm]\n        traefik --\u003e prod[myapp-hello-prod\\n:3013]\n        traefik --\u003e staging[myapp-hello-staging\\n:3012]\n        traefik --\u003e devenv[myapp-hello-dev\\n:3011]\n        prod --\u003e pg_prod[(PostgreSQL prod)]\n        staging --\u003e pg_staging[(PostgreSQL staging)]\n        devenv --\u003e pg_dev[(PostgreSQL dev)]\n\n        subgraph obs[Observability Stack]\n            grafana[Grafana\\n:3100]\n            prometheus[Prometheus] --\u003e|scrape /metrics| prod\n            promtail[Promtail] --\u003e|push logs| loki[Loki]\n            prod --\u003e|OTLP traces| tempo[Tempo]\n        end\n        grafana --\u003e prometheus \u0026 loki \u0026 tempo\n    end\n\n    traefik --\u003e|ACME HTTP-01| letsencrypt[Let's Encrypt]\n    swarm -.-\u003e|DNS| duckdns[apolenkov.duckdns.org]\n```\n\n## Quick Start\n\n**Prerequisites:** Docker and Docker Compose installed locally.\n\n```bash\ngit clone https://github.com/apolenkov/myapp-hello.git\ncd myapp-hello\ndocker compose up --build\n```\n\nThe API is available at `http://localhost:3001`.\n\nFor local development without Docker:\n\n```bash\nnpm install\ncp .env.example .env   # fill in DATABASE_URL\nnpm run dev\n```\n\n## Environment Variables\n\n| Variable       | Required | Default       | Description                                  |\n| -------------- | -------- | ------------- | -------------------------------------------- |\n| `PORT`         | No       | `3001`        | HTTP port the app listens on                 |\n| `NODE_ENV`     | No       | `development` | Runtime environment label                    |\n| `APP_NAME`     | No       | `myapp-hello` | Application name included in responses       |\n| `DATABASE_URL` | No       | —             | PostgreSQL connection string                 |\n| `JWT_SECRET`   | No       | —             | Secret key for JWT verification              |\n| `LOG_LEVEL`    | No       | `info`        | Pino log level (trace/debug/info/warn/error) |\n\nWhen `DATABASE_URL` is not set the app runs without a database and reports `db: \"not configured\"`.\n\n## API Endpoints\n\n| Method | Path            | Auth | Description                           |\n| ------ | --------------- | ---- | ------------------------------------- |\n| GET    | `/v1`           | None | Hello World response with DB status   |\n| GET    | `/health`       | None | Health check — returns `status: \"ok\"` |\n| GET    | `/metrics`      | None | Prometheus metrics (internal only)    |\n| GET    | `/docs`         | None | Swagger UI (OpenAPI 3.0)              |\n| GET    | `/openapi.json` | None | Raw OpenAPI specification             |\n\nProtected routes are secured by a global `JwtAuthGuard`. Use the `@Public()` decorator to opt out\nspecific endpoints from authentication.\n\n## Environments\n\n| Environment | Branch | External Port | URL                                     |\n| ----------- | ------ | ------------- | --------------------------------------- |\n| Production  | `main` | `:3013`       | `https://apolenkov.duckdns.org`         |\n| Staging     | `main` | `:3012`       | `https://staging.apolenkov.duckdns.org` |\n| Dev         | `main` | `:3011`       | `https://dev.apolenkov.duckdns.org`     |\n\nAll three environments deploy from `main` via artifact promotion — the same Docker image (tagged\nwith the commit SHA) is promoted through dev → staging → production. Each environment has its own\nPostgreSQL instance and independent configuration.\n\n## Documentation\n\n- [Architecture](docs/architecture.md) — C4 diagrams (Context, Container, Component, Deployment)\n- [Deployment](docs/deployment.md) — CI/CD pipeline, environments, rollback, secrets\n- [Development](docs/development.md) — Local setup, npm scripts, DB migrations, testing\n- [API Reference](docs/api.md) — Endpoints, authentication, rate limiting\n- [Observability](docs/observability.md) — Monitoring stack, dashboards, alerts, adding new services\n\n## Tech Stack\n\n| Layer             | Technology                                           |\n| ----------------- | ---------------------------------------------------- |\n| Runtime           | Node.js 22 (LTS)                                     |\n| Framework         | NestJS 11 (Express adapter)                          |\n| Language          | TypeScript 5 (strict mode)                           |\n| Database          | PostgreSQL 18 via `node-postgres`                    |\n| Logging           | nestjs-pino (structured JSON via Pino)               |\n| Observability     | OpenTelemetry + Prometheus + Loki + Tempo + Grafana  |\n| Auth              | @nestjs/jwt + global JwtAuthGuard                    |\n| Rate limiting     | @nestjs/throttler (global ThrottlerGuard)            |\n| API docs          | @nestjs/swagger (decorator-driven OpenAPI)           |\n| Testing           | Vitest + @vitest/coverage-v8                         |\n| Linting           | ESLint 9 (sonarjs, unicorn, security, import-x)      |\n| Formatting        | Prettier 3                                           |\n| Architecture lint | dependency-cruiser                                   |\n| Containerization  | Docker (multi-stage build, non-root user, dumb-init) |\n| Orchestration     | Docker Swarm via Dokploy                             |\n| CI/CD             | GitHub Actions                                       |\n| Releases          | semantic-release                                     |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapolenkov%2Fmyapp-hello","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapolenkov%2Fmyapp-hello","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapolenkov%2Fmyapp-hello/lists"}