{"id":35066663,"url":"https://github.com/local-loop-io/localloop-backend","last_synced_at":"2026-05-06T19:32:48.638Z","repository":{"id":329968922,"uuid":"1119486383","full_name":"local-loop-io/localloop-backend","owner":"local-loop-io","description":"Backend API for LocalLoop expressions of interest","archived":false,"fork":false,"pushed_at":"2025-12-21T13:44:54.000Z","size":138,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-24T01:59:15.949Z","etag":null,"topics":["api","backend","express","interest-form","sqlite"],"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/local-loop-io.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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-12-19T10:50:09.000Z","updated_at":"2025-12-21T13:44:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/local-loop-io/localloop-backend","commit_stats":null,"previous_names":["local-loop-io/localloop-backend"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/local-loop-io/localloop-backend","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-loop-io%2Flocalloop-backend","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-loop-io%2Flocalloop-backend/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-loop-io%2Flocalloop-backend/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-loop-io%2Flocalloop-backend/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/local-loop-io","download_url":"https://codeload.github.com/local-loop-io/localloop-backend/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-loop-io%2Flocalloop-backend/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28078030,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-27T02:00:05.897Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["api","backend","express","interest-form","sqlite"],"created_at":"2025-12-27T11:31:43.798Z","updated_at":"2026-05-06T19:32:48.625Z","avatar_url":"https://github.com/local-loop-io.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# localLOOP Backend\n\nBackend service for the localLOOP lab demo — interest registry, city data, and minimal LOOP protocol interop flows.\n\n\u003e This project is an early, low-TRL concept. There are no public pilots or deployments. Lab demo only.\n\n## At a glance\n| Item | Details |\n| --- | --- |\n| Runtime | Bun + Fastify |\n| Data | PostgreSQL (PostGIS), Redis, MinIO |\n| API base | https://loop-api.urbnia.com |\n| Docs | Live OpenAPI at `/openapi.json`, Redoc at `/docs` |\n\n## Quickstart (local)\n```bash\nbun install\ncp .env.example .env          # adjust values as needed\ndocker compose up -d          # start Postgres, Redis, MinIO\nbun run dev                   # API on :8088\nbun test                      # run all tests\n```\n\n## API\n\n### Health\n| Method | Path | Description |\n| --- | --- | --- |\n| `GET` | `/health` | Service + DB status. Returns `503` if DB unreachable. |\n\n### Interest\n| Method | Path | Description |\n| --- | --- | --- |\n| `POST` | `/api/interest` | Submit an Expression of Interest |\n| `GET` | `/api/interest` | List Expressions of Interest |\n| `GET` | `/api/interest/stream` | SSE stream for new interest events |\n\n### Loop demo (MaterialDNA → Offer → Match → Transfer)\n| Method | Path | Description |\n| --- | --- | --- |\n| `POST` | `/api/v1/material` | Register a MaterialDNA record |\n| `GET` | `/api/v1/material/:id` | Retrieve a material by ID |\n| `GET` | `/api/v1/material` | List materials (`limit`, `category`) |\n| `GET` | `/api/v1/node/info` | Return local node metadata for the lab backend |\n| `POST` | `/api/v1/product` | Register a ProductDNA record |\n| `GET` | `/api/v1/product/:id` | Retrieve a product by ID |\n| `GET` | `/api/v1/product` | List products (`limit`, `category`) |\n| `POST` | `/api/v1/offer` | Create an Offer |\n| `GET` | `/api/v1/offer/:id` | Retrieve an offer by ID |\n| `GET` | `/api/v1/offer` | List offers (`limit`, `status`) |\n| `POST` | `/api/v1/match` | Record a Match |\n| `GET` | `/api/v1/match/:id` | Retrieve a match by ID |\n| `GET` | `/api/v1/match` | List matches (`limit`) |\n| `POST` | `/api/v1/transfer` | Record a Transfer |\n| `GET` | `/api/v1/transfer/:id` | Retrieve a transfer by ID |\n| `GET` | `/api/v1/transfer` | List transfers (`limit`) |\n| `POST` | `/api/v1/material-status` | Record a material status update |\n| `GET` | `/api/v1/events` | List loop events (`limit`) |\n| `GET` | `/api/v1/stream` | SSE stream for loop events |\n| `POST` | `/api/v1/relay` | Relay a supported lab loop event from another node |\n\n### Federation\n| Method | Path | Description |\n| --- | --- | --- |\n| `GET` | `/api/v1/federation/nodes` | List known federation nodes |\n| `POST` | `/api/v1/federation/handshake` | Register a federation node (lab-only handshake) |\n\n### Cities\n| Method | Path | Description |\n| --- | --- | --- |\n| `GET` | `/api/cities` | List demo cities |\n| `GET` | `/api/cities/:slug` | City detail |\n| `GET` | `/api/cities/geojson` | GeoJSON FeatureCollection |\n\n### Other\n| Method | Path | Description |\n| --- | --- | --- |\n| `GET` | `/api/metrics` | In-memory service metrics snapshot |\n| `GET` | `/api/privacy` | Privacy notice |\n| `GET` | `/openapi.json` | OpenAPI spec (auto-generated) |\n| `GET` | `/docs` | Redoc UI |\n\nLOOP write routes accept both `application/json` and `application/ld+json`.\nThe backend also serves `GET /api/v1/node/info` as a minimal lab-only node metadata endpoint.\nSpec endpoints that remain unimplemented in this repo are `/api/v1/material/search`, `/api/v1/signals`, `/api/v1/transaction`, `/api/v1/federate/announce`, and `/api/v1/federate/offer`.\n\n## Environment variables\n\nSee `.env.example` for the full list with descriptions. Key variables:\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `DATABASE_URL` | — | Postgres connection string (required) |\n| `DATABASE_SSL` | `false` | Enable TLS for Postgres |\n| `DB_POOL_SIZE` | `20` | Max pool connections |\n| `DB_IDLE_TIMEOUT_MS` | `30000` | Close idle connections after ms |\n| `DB_CONNECTION_TIMEOUT_MS` | `5000` | Fail if no pool slot in ms |\n| `REDIS_URL` | — | Redis connection string |\n| `MINIO_SECRET_KEY` | — | MinIO secret (required) |\n| `ALLOWED_ORIGINS` | `https://local-loop-io.github.io` | CORS allowlist (comma-separated) |\n| `RATE_LIMIT_MAX` | `60` | Global rate limit per window |\n| `RATE_LIMIT_WRITE_MAX` | `20` | Write route rate limit per window |\n| `REQUEST_TIMEOUT_MS` | `30000` | Server connection timeout |\n| `AUTH_ENABLED` | `false` | Enable BetterAuth |\n| `API_KEY_ENABLED` | `false` | Require `X-API-Key` on write routes |\n| `RUN_MIGRATIONS` | `true` | Auto-run DB migrations on startup |\n\nIn `NODE_ENV=production` the server refuses to start with missing or weak secrets.\n\n## Repo layout\n```\nsrc/\n  config.ts        env validation (Zod)\n  server.ts        Fastify app setup\n  routes/          one file per route group\n  db/\n    pool.ts        pg connection pool\n    migrations/    numbered .sql files\n    loop.ts        loop entity queries\n  realtime/        SSE stream handlers\n  security/        API key middleware\nscripts/           lab demo + federation scripts\ndeploy/            systemd service + nginx example\ntests/             Bun test suite\n```\n\n## Notes\n- Lab demo only. No public pilots or deployments.\n- The normative protocol reference is [loop-protocol](https://github.com/local-loop-io/loop-protocol).\n\n## Links\n- Protocol spec: https://github.com/local-loop-io/loop-protocol\n- Docs hub: https://local-loop-io.github.io\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocal-loop-io%2Flocalloop-backend","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flocal-loop-io%2Flocalloop-backend","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocal-loop-io%2Flocalloop-backend/lists"}