{"id":33613126,"url":"https://github.com/typelets/typelets-api","last_synced_at":"2026-03-09T04:02:47.049Z","repository":{"id":313934764,"uuid":"1053528418","full_name":"typelets/typelets-api","owner":"typelets","description":"A secure, encrypted notes API with zero-knowledge architecture, client-side encryption support, and comprehensive user management the backend powering Typelets with PostgreSQL and TypeScript","archived":false,"fork":false,"pushed_at":"2025-11-30T19:43:13.000Z","size":624,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-06T08:39:48.570Z","etag":null,"topics":["end-to-end-encryption","notes-app","secure-notes","typelets","typelets-api"],"latest_commit_sha":null,"homepage":"https://typelets.com","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/typelets.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","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-09-09T15:13:44.000Z","updated_at":"2025-11-30T19:43:15.000Z","dependencies_parsed_at":"2025-09-24T13:03:10.888Z","dependency_job_id":"4bef3c02-0b12-40d9-b8ad-366fca4e6bbc","html_url":"https://github.com/typelets/typelets-api","commit_stats":null,"previous_names":["typelets/typelets-api"],"tags_count":60,"template":false,"template_full_name":null,"purl":"pkg:github/typelets/typelets-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelets%2Ftypelets-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelets%2Ftypelets-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelets%2Ftypelets-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelets%2Ftypelets-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typelets","download_url":"https://codeload.github.com/typelets/typelets-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typelets%2Ftypelets-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30282543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T02:57:19.223Z","status":"ssl_error","status_checked_at":"2026-03-09T02:56:26.373Z","response_time":61,"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":["end-to-end-encryption","notes-app","secure-notes","typelets","typelets-api"],"created_at":"2025-12-01T01:02:36.850Z","updated_at":"2026-03-09T04:02:47.037Z","avatar_url":"https://github.com/typelets.png","language":"TypeScript","readme":"# Typelets API\n\n[![Version](https://img.shields.io/github/package-json/v/typelets/typelets-api)](https://github.com/typelets/typelets-api/releases)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Node.js](https://img.shields.io/badge/Node.js-22%2B-green.svg)](https://nodejs.org/)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.8%2B-blue.svg)](https://www.typescriptlang.org/)\n[![Hono](https://img.shields.io/badge/Hono-4.8%2B-orange.svg)](https://hono.dev/)\n[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-15%2B-blue.svg)](https://www.postgresql.org/)\n[![pnpm](https://img.shields.io/badge/pnpm-9.15.0%2B-yellow.svg)](https://pnpm.io/)\n\nThe backend API for the [Typelets Application](https://github.com/typelets/typelets-app) - a secure, encrypted notes management system built with TypeScript, Hono, and PostgreSQL. Features end-to-end encryption support, file attachments, and folder organization.\n\n## Table of Contents\n\n- [Features](#features)\n- [Tech Stack](#tech-stack)\n- [Prerequisites](#prerequisites)\n- [Local Development Setup](#local-development-setup)\n  - [Quick Start](#quick-start)\n  - [Development Workflow](#development-workflow)\n- [Alternative Installation Methods](#alternative-installation-methods)\n- [Available Scripts](#available-scripts)\n- [API Endpoints](#api-endpoints)\n  - [Public Endpoints](#public-endpoints)\n  - [Authentication](#authentication)\n  - [Interactive Documentation](#interactive-documentation)\n- [Database Schema](#database-schema)\n- [Security Features](#security-features)\n- [Environment Variables](#environment-variables)\n- [Monitoring with Grafana Cloud](#monitoring-with-grafana-cloud)\n  - [Features](#features-1)\n  - [Configuration](#configuration)\n  - [What Gets Monitored](#what-gets-monitored)\n- [Development](#development)\n  - [Project Structure](#project-structure)\n  - [Type Safety](#type-safety)\n- [Docker Support](#docker-support)\n- [Production Deployment](#production-deployment)\n- [Contributing](#contributing)\n  - [Getting Started](#getting-started)\n  - [Commit Message Format](#commit-message-format)\n  - [Pull Request Process](#pull-request-process)\n  - [Reporting Issues](#reporting-issues)\n  - [Security Vulnerabilities](#security-vulnerabilities)\n- [License](#license)\n- [Acknowledgments](#acknowledgments)\n\n## Features\n\n- 🔐 **Secure Authentication** via Clerk\n- 📝 **Encrypted Notes** with client-side encryption support\n- 📁 **Folder Organization** with nested folder support\n- 📎 **File Attachments** with encrypted storage\n- 🏷️ **Tags \u0026 Search** for easy note discovery\n- 🗑️ **Trash \u0026 Archive** functionality\n- ⚡ **Fast \u0026 Type-Safe** with TypeScript and Hono\n- 🐘 **PostgreSQL** with Drizzle ORM\n- 🚀 **Valkey/Redis Caching** for high-performance data access with cluster support\n- 📊 **Observability** with Grafana Cloud and OpenTelemetry for distributed tracing, metrics, and logging\n- 💻 **Code Execution** via self-hosted Piston engine\n- 🛡️ **Comprehensive Rate Limiting** for HTTP, file uploads, and code execution\n- 🏥 **Health Checks** with detailed system status and readiness probes\n- 📈 **Structured Logging** with automatic event tracking and error capture\n\n## Tech Stack\n\n- **Runtime**: Node.js 22+ (LTS recommended)\n- **Framework**: [Hono](https://hono.dev/) - Fast, lightweight web framework\n- **Database**: PostgreSQL with [Drizzle ORM](https://orm.drizzle.team/)\n- **Cache**: Valkey/Redis Cluster for high-performance caching\n- **Authentication**: [Clerk](https://clerk.com/)\n- **Validation**: [Zod](https://zod.dev/)\n- **Observability**: [Grafana Cloud](https://grafana.com/products/cloud/) with [OpenTelemetry](https://opentelemetry.io/) for tracing, metrics, and logging\n- **Logging**: Structured JSON logging with automatic error capture\n- **TypeScript**: Strict mode enabled for type safety\n\n## Prerequisites\n\n- Node.js 22+ (LTS recommended)\n- pnpm 9.15.0+\n- PostgreSQL database (local installation or Docker)\n- Clerk account for authentication ([sign up here](https://dashboard.clerk.com))\n- Valkey/Redis cluster for caching (optional - improves performance)\n- Grafana Cloud account for monitoring (optional - [sign up here](https://grafana.com/products/cloud/))\n- Piston code execution engine (optional - [self-hosted](https://github.com/engineer-man/piston))\n\n## Local Development Setup\n\n**Recommended approach for development: PostgreSQL in Docker + API with npm for hot reload and easy debugging**\n\n### Quick Start\n\n1. **Clone and install dependencies:**\n\n```bash\ngit clone https://github.com/typelets/typelets-api.git\ncd typelets-api\npnpm install\n```\n\n2. **Start PostgreSQL with Docker:**\n\n```bash\n# Start PostgreSQL database for local development\ndocker run --name typelets-postgres \\\n  -e POSTGRES_PASSWORD=devpassword \\\n  -e POSTGRES_DB=typelets_local \\\n  -p 5432:5432 -d postgres:15\n```\n\n3. **Set up environment variables:**\n\n```bash\ncp .env.example .env\n```\n\n4. **Configure environment variables:**\n   - Create a free account at [Clerk Dashboard](https://dashboard.clerk.com)\n   - Create a new application\n   - (Optional) Set up self-hosted [Piston](https://github.com/engineer-man/piston) for code execution\n   - Update `.env` with your settings:\n\n   ```env\n   CLERK_SECRET_KEY=sk_test_your_actual_clerk_secret_key_from_dashboard\n   CORS_ORIGINS=http://localhost:5173,http://localhost:3000\n   # Optional: For code execution features (self-hosted Piston)\n   PISTON_API_URL=http://localhost:2000\n   ```\n\n5. **Set up database schema:**\n\n```bash\npnpm run db:push\n```\n\n6. **Start development server:**\n\n```bash\npnpm run dev\n```\n\n🎉 **Your API is now running at `http://localhost:3000`**\n\nThe development server will automatically restart when you make changes to any TypeScript files.\n\n### Development Workflow\n\n```bash\n# Start/stop database\ndocker start typelets-postgres    # Start existing container\ndocker stop typelets-postgres     # Stop when done\n\n# API development\npnpm run dev                      # Auto-restart development server\npnpm run build                    # Test production build\npnpm run lint                     # Check code quality\n```\n\n**Development Features:**\n\n- ⚡ **Auto-restart**: Server automatically restarts when you save TypeScript files\n- 📝 **Terminal history preserved**: See all your logs and errors\n- 🚀 **Fast compilation**: Uses tsx with esbuild for quick rebuilds\n\n## Alternative Installation Methods\n\n### Full Docker Setup (for testing production-like environment)\n\n```bash\n# 1. Start PostgreSQL\ndocker run --name typelets-postgres -e POSTGRES_PASSWORD=devpassword -e POSTGRES_DB=typelets_local -p 5432:5432 -d postgres:15\n\n# 2. Build and run API in Docker\ndocker build -t typelets-api .\ndocker run -p 3000:3000 --env-file .env typelets-api\n```\n\n### Local PostgreSQL Installation\n\nIf you prefer to install PostgreSQL locally instead of Docker:\n\n- Install PostgreSQL on your machine\n- Create database: `createdb typelets_local`\n- Update `.env`: `DATABASE_URL=postgresql://postgres:your_password@localhost:5432/typelets_local`\n\n## Available Scripts\n\n- `pnpm run dev` - Start development server with auto-restart\n- `pnpm run build` - Build for production\n- `pnpm start` - Start production server\n- `pnpm run lint` - Run ESLint\n- `pnpm run format` - Format code with Prettier\n- `pnpm run db:generate` - Generate database migrations\n- `pnpm run db:push` - Apply database schema changes\n- `pnpm run db:studio` - Open Drizzle Studio for database management\n\n## API Endpoints\n\n📚 **Complete API documentation with interactive examples: [https://api.typelets.com/docs](https://api.typelets.com/docs)** (Swagger/OpenAPI)\n\nThe API provides comprehensive REST endpoints for:\n\n- **Users** - Profile management and account deletion\n- **Folders** - Hierarchical folder organization with nested support\n- **Notes** - Full CRUD with encryption support, pagination, filtering, and search\n- **File Attachments** - Encrypted file uploads and downloads\n- **Code Execution** - Self-hosted Piston engine for running code in multiple languages\n- **Health Checks** - System health checks and status monitoring\n\n### Public Endpoints\n\n| Endpoint      | Description                              |\n| ------------- | ---------------------------------------- |\n| `GET /`       | API information and version              |\n| `GET /health` | Enhanced health check with system status |\n\n### Authentication\n\nAll `/api/*` endpoints require authentication via Bearer token:\n\n```\nAuthorization: Bearer \u003cclerk_jwt_token\u003e\n```\n\n### Interactive Documentation\n\nVisit the Swagger UI at [/docs](https://api.typelets.com/docs) for:\n\n- Complete endpoint reference with request/response schemas\n- Interactive \"Try it out\" functionality\n- Example requests and responses\n- Schema definitions and validation rules\n\n## Database Schema\n\nThe application uses the following main tables:\n\n- `users` - User profiles synced from Clerk\n- `folders` - Hierarchical folder organization\n- `notes` - Encrypted notes with metadata\n- `file_attachments` - Encrypted file attachments\n\n## Security Features\n\n- **Authentication**: All endpoints protected with Clerk JWT verification\n- **Encryption Ready**: Schema supports client-side encryption for notes and files\n- **Input Validation**: Comprehensive Zod schemas for all inputs\n- **SQL Injection Protection**: Parameterized queries via Drizzle ORM\n- **CORS Configuration**: Configurable allowed origins\n- **File Size Limits**: Configurable limits (default: 50MB per file, 1GB total per note)\n\n## Environment Variables\n\n| Variable                       | Description                                      | Required | Default                          |\n| ------------------------------ | ------------------------------------------------ | -------- | -------------------------------- |\n| `DATABASE_URL`                 | PostgreSQL connection string                     | Yes      | -                                |\n| `CLERK_SECRET_KEY`             | Clerk secret key for JWT verification            | Yes      | -                                |\n| `CORS_ORIGINS`                 | Comma-separated list of allowed CORS origins     | Yes      | -                                |\n| `PORT`                         | Server port                                      | No       | 3000                             |\n| `NODE_ENV`                     | Environment (development/production)             | No       | development                      |\n| **Caching (Optional)**         |                                                  |          |                                  |\n| `VALKEY_HOST`                  | Valkey/Redis cluster hostname                    | No       | -                                |\n| `VALKEY_PORT`                  | Valkey/Redis cluster port                        | No       | 6379                             |\n| **Monitoring (Optional)**      |                                                  |          |                                  |\n| `OTEL_EXPORTER_OTLP_ENDPOINT`  | Grafana Cloud OTLP endpoint (prod only)          | No       | -                                |\n| `GRAFANA_CLOUD_API_KEY`        | Base64 encoded Grafana Cloud credentials         | No       | -                                |\n| `OTEL_SERVICE_NAME`            | Service name for OpenTelemetry                   | No       | typelets-api                     |\n| `OTEL_ENABLED`                 | Force enable OTEL in dev (not recommended)       | No       | false                            |\n| **Rate Limiting**              |                                                  |          |                                  |\n| `HTTP_RATE_LIMIT_WINDOW_MS`    | HTTP rate limit window in milliseconds           | No       | 900000 (15 min)                  |\n| `HTTP_RATE_LIMIT_MAX_REQUESTS` | Max HTTP requests per window                     | No       | 1000                             |\n| `HTTP_FILE_RATE_LIMIT_MAX`     | Max file operations per window                   | No       | 100                              |\n| `CODE_EXEC_RATE_LIMIT_MAX`     | Max code executions per window                   | No       | 100 (dev), 50 (prod)             |\n| `CODE_EXEC_RATE_WINDOW_MS`     | Code execution rate limit window in milliseconds | No       | 900000 (15 min)                  |\n| **File \u0026 Storage**             |                                                  |          |                                  |\n| `MAX_FILE_SIZE_MB`             | Maximum size per file in MB                      | No       | 50                               |\n| `MAX_NOTE_SIZE_MB`             | Maximum total attachments per note in MB         | No       | 1024 (1GB)                       |\n| `FREE_TIER_STORAGE_GB`         | Free tier storage limit in GB                    | No       | 1                                |\n| `FREE_TIER_NOTE_LIMIT`         | Free tier note count limit                       | No       | 100                              |\n| **Code Execution (Optional)**  |                                                  |          |                                  |\n| `PISTON_API_URL`               | Self-hosted Piston API URL                       | No\\*     | http://localhost:2000            |\n\n\\*Required only for code execution features (self-hosted Piston)\n\n## Monitoring with Grafana Cloud\n\n⚠️ **Monitoring is completely optional** - The API works perfectly without it.\n\nThe API integrates with [Grafana Cloud](https://grafana.com/products/cloud/) using [OpenTelemetry](https://opentelemetry.io/) for comprehensive observability with distributed tracing, metrics collection, and log aggregation.\n\n### Features\n\n- **Distributed Tracing**: Automatic instrumentation for HTTP requests, database queries, and cache operations\n- **Metrics Collection**: Real-time metrics exported every 60 seconds\n- **Log Aggregation**: Structured JSON logs sent to Grafana Loki\n- **Automatic Instrumentation**: Zero-code instrumentation for:\n  - HTTP/HTTPS requests (Hono framework)\n  - PostgreSQL database queries\n  - Redis/Upstash cache operations\n- **Performance Monitoring**: Request duration, latency, and throughput tracking\n- **Error Tracking**: Automatic error capture with full context and stack traces\n- **User Context**: Requests are automatically tagged with user IDs\n- **Environment Tracking**: Separate monitoring for development and production\n\n### Configuration\n\n**Local Development Setup:**\n\n1. **Sign up for Grafana Cloud** (free tier available):\n   - Visit https://grafana.com/products/cloud/\n\n2. **Get your credentials:**\n   - Go to **Connections** → **Add new connection** → **OpenTelemetry**\n   - Copy the OTLP endpoint URL (e.g., `https://otlp-gateway-prod-\u003cregion\u003e.grafana.net/otlp`)\n   - Generate a token for authentication\n\n3. **Start Grafana Alloy locally:**\n   ```bash\n   # Set your Grafana Cloud token in .env.local\n   echo \"GRAFANA_CLOUD_TOKEN=glc_your_token_here\" \u003e\u003e .env.local\n\n   # Start Alloy with Docker Compose\n   docker compose -f docker-compose.alloy.yml up -d\n   ```\n\n4. **Configure your application:**\n   Add to `.env.local`:\n   ```env\n   # Point to local Alloy instance\n   OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\n   OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf\n   OTEL_SERVICE_NAME=typelets-api\n   OTEL_RESOURCE_ATTRIBUTES=deployment.environment=development,service.name=typelets-api\n   ```\n\n5. **Start development server:**\n   ```bash\n   pnpm run dev\n   ```\n\nYou should see logs appearing in Grafana Cloud Loki with `service_name=\"typelets-api\"`.\n\n**Production Setup:**\n\nIn production (ECS), the Alloy sidecar runs in the same task as the API container. See the [Production Deployment](#production-deployment) section for details.\n\n**Important Notes:**\n- Local dev sends to Alloy at `localhost:4318`\n- Alloy forwards to Grafana Cloud with authentication\n- All telemetry (logs, traces, metrics) flows through Alloy\n- If Alloy is not running, the app continues working normally (telemetry is optional)\n\n### What Gets Monitored\n\n**Automatic Instrumentation:**\n- HTTP requests (method, path, status code, duration)\n- PostgreSQL queries (operation, table, duration)\n- Redis/Upstash operations (get, set, delete with cache hit/miss tracking)\n\n**Structured Logging:**\n- Authentication events (login, logout, token refresh)\n- Rate limiting violations\n- Security events (failed auth, suspicious activity)\n- Billing limit violations\n- File upload events and storage operations\n- HTTP request/response logs\n- Database query performance\n- Cache operations and hit rates\n- Business events (note creation, folder operations, etc.)\n\nAll logs, traces, and metrics are automatically sent to Grafana Cloud where you can:\n- Visualize request traces with flame graphs\n- Create custom dashboards for metrics\n- Set up alerts for errors and performance issues\n- Search and analyze logs with LogQL\n- Correlate logs, metrics, and traces in one place\n\n## Development\n\n### Project Structure\n\n```\nsrc/\n├── db/\n│   ├── index.ts        # Database connection\n│   └── schema.ts       # Database schema definitions\n├── lib/\n│   ├── cache.ts        # Valkey/Redis cluster caching layer\n│   ├── cache-keys.ts   # Centralized cache key patterns and TTL values\n│   ├── logger.ts       # Structured logging with automatic error capture\n│   └── validation.ts   # Zod validation schemas\n├── middleware/\n│   ├── auth.ts         # Authentication middleware\n│   ├── rate-limit.ts   # Rate limiting middleware\n│   ├── security.ts     # Security headers middleware\n│   └── usage.ts        # Storage and usage limit enforcement\n├── routes/\n│   ├── code.ts         # Code execution routes (Piston engine)\n│   ├── files.ts        # File attachment routes\n│   ├── folders.ts      # Folder management routes with caching\n│   ├── notes.ts        # Note management routes\n│   └── users.ts        # User profile routes\n├── types/\n│   └── index.ts        # TypeScript type definitions\n└── server.ts           # Application entry point\n```\n\n### Type Safety\n\nThis project uses TypeScript in strict mode with comprehensive type definitions. All database operations, API inputs, and responses are fully typed.\n\n## Docker Support\n\n### For Local Testing with Docker Containers\n\nThe API can be run in Docker containers for local testing. The architecture separates the API from the database:\n\n```bash\n# 1. Start PostgreSQL container for local testing\ndocker run --name typelets-postgres -e POSTGRES_PASSWORD=devpassword -e POSTGRES_DB=typelets_local -p 5432:5432 -d postgres:15\n\n# 2. Build your API container\ndocker build -t typelets-api .\n\n# 3. Run API container for local testing\ndocker run -p 3000:3000 --env-file .env typelets-api\n\n# Run with environment file\ndocker run -p 3000:3000 \\\n  -e NODE_ENV=development \\\n  --env-file .env \\\n  typelets-api\n```\n\n**This Docker setup is for local development and testing only.**\n\n### Production vs Local Architecture\n\n| Environment       | API                         | Database                    | Configuration       |\n| ----------------- | --------------------------- | --------------------------- | ------------------- |\n| **Local Testing** | Docker container OR npm dev | Docker PostgreSQL container | `.env` file         |\n| **Production**    | ECS container               | AWS RDS PostgreSQL          | ECS task definition |\n\n## Production Deployment\n\n**⚠️ Important: Production deployment is completely different from local testing setup.**\n\nThis application is designed for production deployment using AWS ECS (Elastic Container Service) with a **Grafana Alloy sidecar** for observability.\n\n### Production Architecture\n\n```\n┌─────────────────────────────────────────┐\n│         ECS Task (Fargate)              │\n│                                         │\n│  ┌──────────────┐   ┌──────────────┐  │\n│  │ typelets-api │──▶│ grafana-alloy│  │\n│  │ (Port 3000)  │   │ (Port 4318)  │  │\n│  └──────────────┘   └──────┬───────┘  │\n│                             │          │\n└─────────────────────────────┼──────────┘\n                              │\n                              ▼\n                    Grafana Cloud OTLP\n```\n\nThe API sends telemetry (logs, traces, metrics) to a local Alloy sidecar at `http://localhost:4318`, which then forwards to Grafana Cloud.\n\n### Production Infrastructure\n\n- **API**: ECS containers running in AWS\n- **Database**: AWS RDS PostgreSQL (not Docker containers)\n- **Monitoring**: Grafana Alloy sidecar + Grafana Cloud\n- **Environment Variables**: ECS task definitions (not `.env` files)\n- **Secrets**: AWS Parameter Store or Secrets Manager\n- **Container Registry**: Amazon ECR\n\n### Deployment Steps\n\n#### 1. Build and Push Docker Images\n\n```bash\n# Build and push the API image\npnpm run build\ndocker build -t typelets-api:latest .\ndocker tag typelets-api:latest YOUR_ECR_REPO/typelets-api:latest\ndocker push YOUR_ECR_REPO/typelets-api:latest\n\n# Build and push the Alloy sidecar image\ndocker build -f Dockerfile.alloy -t grafana-alloy:latest .\ndocker tag grafana-alloy:latest YOUR_ECR_REPO/grafana-alloy:latest\ndocker push YOUR_ECR_REPO/grafana-alloy:latest\n```\n\n#### 2. Create ECS Task Definition\n\nYour ECS task definition should include **two containers**:\n\n**Container 1: typelets-api**\n- Image: `YOUR_ECR_REPO/typelets-api:latest`\n- Port: 3000\n- Essential: `true`\n- Environment variables:\n  - `OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318`\n  - `OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf`\n  - `OTEL_SERVICE_NAME=typelets-api`\n  - All other app environment variables\n\n**Container 2: grafana-alloy**\n- Image: `YOUR_ECR_REPO/grafana-alloy:latest`\n- Ports: 4318, 4317\n- Essential: `false`\n- Environment variables:\n  - `GRAFANA_CLOUD_TOKEN=your_grafana_cloud_token`\n  - `GRAFANA_CLOUD_ENDPOINT=your_otlp_gateway_endpoint_here`\n  - `GRAFANA_CLOUD_INSTANCE_ID=your_instance_id`\n\n**Task Resources:**\n- CPU: 1024 (1 vCPU)\n- Memory: 2048 (2GB)\n- Network Mode: `awsvpc` (required for localhost communication)\n\n#### 3. Register and Deploy\n\n```bash\n# Register the task definition\naws ecs register-task-definition \\\n  --cli-input-json file://ecs-task-definition.json \\\n  --region us-east-1\n\n# Update the service\naws ecs update-service \\\n  --cluster YOUR_CLUSTER_NAME \\\n  --service YOUR_SERVICE_NAME \\\n  --task-definition typelets-api-td \\\n  --force-new-deployment \\\n  --region us-east-1\n```\n\n### Important Notes\n\n**Local Development with Grafana:**\n- Run Alloy locally: `docker compose -f docker-compose.alloy.yml up -d`\n- Set `GRAFANA_CLOUD_TOKEN` in `.env.local`\n- Logs will appear in Grafana Cloud Loki\n\n**Production Secrets:**\n- Never commit ECS task definitions (they contain secrets)\n- Task definition files are in `.gitignore`\n- Store sensitive values in AWS Secrets Manager or Parameter Store\n\n**Monitoring:**\n- CloudWatch Logs: `/ecs/typelets-backend-td` (app logs)\n- CloudWatch Logs: `/ecs/grafana-alloy` (Alloy logs)\n- Grafana Cloud Loki: Structured app logs with trace correlation\n\n**Health Checks:**\n- App container: Uses `/health` endpoint\n- Alloy container: No health check needed (essential: false)\n\n### Troubleshooting\n\n**Container fails with \"Cannot find module './instrumentation.js'\":**\n- This is fixed in the Dockerfile by copying `instrumentation.js` to production\n- Rebuild and push the image\n\n**Logs not appearing in Grafana:**\n- Check Alloy container logs in CloudWatch\n- Verify `GRAFANA_CLOUD_TOKEN` is set correctly\n- Ensure app is sending to `http://localhost:4318`\n\n**Production vs Local:**\n- **Local**: Uses `.env` files and Docker containers for testing\n- **Production**: Uses ECS task definitions and AWS RDS for real deployment\n- **Never use**: Local testing setup in production\n\n## Contributing\n\nWe welcome contributions from the community!\n\n### Getting Started\n\n1. **Fork** the repository on GitHub\n2. **Clone** your fork locally:\n   ```bash\n   git clone https://github.com/your-username/typelets-api.git\n   cd typelets-api\n   ```\n3. **Install dependencies**: `pnpm install`\n4. **Set up environment**: `cp .env.example .env`\n5. **Start PostgreSQL**:\n   ```bash\n   docker run --name typelets-postgres \\\n     -e POSTGRES_PASSWORD=devpassword \\\n     -e POSTGRES_DB=typelets_local \\\n     -p 5432:5432 -d postgres:15\n   ```\n6. **Apply database schema**: `pnpm run db:push`\n7. **Start development**: `pnpm run dev`\n\n### Commit Message Format\n\nWe use [Conventional Commits](https://www.conventionalcommits.org/) for automatic versioning and changelog generation:\n\n- `feat:` New feature (minor version bump)\n- `fix:` Bug fix (patch version bump)\n- `docs:` Documentation changes\n- `style:` Code style changes (formatting, etc.)\n- `refactor:` Code refactoring\n- `perf:` Performance improvements\n- `test:` Adding or updating tests\n- `chore:` Maintenance tasks\n- `ci:` CI/CD changes\n\n**Examples:**\n\n```bash\nfeat(auth): add refresh token rotation\nfix(files): resolve file upload size validation\nfeat(api)!: change authentication header format\n```\n\n### Pull Request Process\n\n1. Create a feature branch: `git checkout -b feature/your-feature-name`\n2. Make your changes and commit using conventional commits\n3. Run linting and tests: `pnpm run lint \u0026\u0026 pnpm run build`\n4. Push to your fork and create a Pull Request\n5. Ensure all CI checks pass\n6. Wait for review and address any feedback\n\n### Reporting Issues\n\nWhen reporting bugs, please include:\n\n- Clear description of the issue\n- Steps to reproduce\n- Expected vs actual behavior\n- Environment details (OS, Node version)\n- Error messages or logs if applicable\n\n### Security Vulnerabilities\n\n**DO NOT** report security vulnerabilities through public GitHub issues. Please use GitHub's private vulnerability reporting feature or contact the maintainers directly.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\n- [Hono](https://hono.dev/) for the excellent web framework\n- [Drizzle ORM](https://orm.drizzle.team/) for type-safe database operations\n- [Clerk](https://clerk.com/) for authentication services\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelets%2Ftypelets-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypelets%2Ftypelets-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypelets%2Ftypelets-api/lists"}