{"id":50360438,"url":"https://github.com/geevensingh/jotjson","last_synced_at":"2026-05-30T01:05:45.639Z","repository":{"id":354285614,"uuid":"1214680073","full_name":"geevensingh/jotjson","owner":"geevensingh","description":"A place to input, display, and store json.","archived":false,"fork":false,"pushed_at":"2026-05-26T06:09:57.000Z","size":5983,"stargazers_count":1,"open_issues_count":147,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T06:15:07.018Z","etag":null,"topics":["angular","azure","azure-functions","azure-static-web-apps","bicep","cosmos-db","developer-tools","json","json-editor","json-tree","json-viewer","jsonc","monaco-editor","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/geevensingh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-18T22:42:30.000Z","updated_at":"2026-05-26T05:04:53.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/geevensingh/jotjson","commit_stats":null,"previous_names":["geevensingh/jotjson"],"tags_count":44,"template":false,"template_full_name":null,"purl":"pkg:github/geevensingh/jotjson","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geevensingh%2Fjotjson","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geevensingh%2Fjotjson/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geevensingh%2Fjotjson/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geevensingh%2Fjotjson/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/geevensingh","download_url":"https://codeload.github.com/geevensingh/jotjson/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geevensingh%2Fjotjson/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33676200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"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":["angular","azure","azure-functions","azure-static-web-apps","bicep","cosmos-db","developer-tools","json","json-editor","json-tree","json-viewer","jsonc","monaco-editor","typescript"],"created_at":"2026-05-30T01:05:44.795Z","updated_at":"2026-05-30T01:05:45.631Z","avatar_url":"https://github.com/geevensingh.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JotJSON\n\nA place to **input, store, and display JSON**. Paste or type JSON (or JSONC)\non the left and it is parsed, formatted, and rendered as a searchable tree on\nthe right. Anonymous use is the default - signing in unlocks persistent,\nshareable links, history, and formatting rules (planned).\n\nProduction site: **https://jotjson.com** (target).\nPreview: https://ambitious-pond-000670a0f.7.azurestaticapps.net/\n\n[`DESIGN_SPEC.md`](./DESIGN_SPEC.md) is the authoritative product and\narchitecture spec.\n\n## Tech stack\n\n| Layer      | Choice                                                      |\n| ---------- | ----------------------------------------------------------- |\n| Frontend   | Angular 19 (standalone + Signals), Angular Material, SCSS   |\n| Editor     | Monaco (lazy-loaded), [`jsonc-parser`](https://www.npmjs.com/package/jsonc-parser) for JSON/JSONC parsing |\n| Backend    | Azure Functions v4, TypeScript (Node 24)                    |\n| Data       | Azure Cosmos DB (serverless, NoSQL)                         |\n| Auth       | MSAL Angular + Microsoft Entra External ID                  |\n| Hosting    | Azure Static Web Apps with managed Functions                |\n| IaC        | Bicep (`/infra`)                                            |\n| Testing    | Karma + Jasmine (frontend); Jest (API)                      |\n| CI/CD      | GitHub Actions (build, test, Bicep validate, SWA deploy)    |\n\nNode **24** is required locally and in CI (pinned via `.nvmrc`, engines, and\nworkflow `node-version`).\n\n## Repository layout\n\n```\nsrc/               Angular app (standalone components under core/shared/features)\n  styles/          Global SCSS (Material theme, design tokens)\n  environments/    environment.ts (gitignored) + example + interface + prod\napi/               Azure Functions (TypeScript)\ninfra/             Bicep templates\npublic/            Static assets copied as-is at build\nscripts/           Repo tooling (check-ascii.mjs, generate-icons.mjs, ...)\n.github/           Workflows (ci.yml, cd.yml, infra.yml) + dependabot.yml\n.vscode/           Launch + tasks configs (ng serve / ng test in Chrome)\nDESIGN_SPEC.md     Product + architecture source of truth\nAGENTS.md          Coding/AI-agent instructions (linted against by humans too)\nCONTRIBUTING.md    Contributor guide\nkarma.conf.js      Karma config with ChromeHeadlessCI launcher\nproxy.conf.json    ng serve proxy that forwards /api/* to func start on :7071\n```\n\n## Prerequisites\n\n- Node **24** (pinned via `.nvmrc`; works with `nvm use` or `fnm use`)\n- npm 10+\n- For API local dev: Azure Functions Core Tools v4\n- For infra: Azure CLI + Bicep\n- A Chromium-family browser on PATH for `npm test`\n\nDetailed install instructions (by OS, with verification steps and\ntroubleshooting) are in [PREREQUISITES.md](PREREQUISITES.md).\n\n## Setup\n\n```bash\nnpm install\n(cd api \u0026\u0026 npm install)\n\n# Web env: copy the template and fill in Entra values for local sign-in.\ncp src/environments/environment.example.ts src/environments/environment.ts\n\n# API env: copy the template and fill in Cosmos + Entra values.\ncp api/local.settings.sample.json api/local.settings.json\n```\n\n`environment.ts` and `api/local.settings.json` are gitignored. For CI, the\nworkflow copies `environment.example.ts` over `environment.ts` unchanged -\nproduction builds source their real values from `environment.prod.ts`, which\nCD bakes from GitHub secrets.\n\n## Running locally\n\nThe Angular dev server proxies `/api/*` to the local Functions host\n(`proxy.conf.json` -\u003e `http://localhost:7071`), so both pieces need to be\nrunning to exercise the full stack.\n\n**Quick start (Windows):**\n\n```powershell\n.\\scripts\\dev.ps1\n```\n\n`scripts/dev.ps1` checks prereqs, runs `npm install` if needed, verifies\nyour env files exist, and opens a Windows Terminal with three tabs:\n`web` (ng serve), `api` (func start), and `tests` (ng test + jest\n--watch split pane). Use `-SkipTests` to skip the tests tab.\n\nIf a previous run left zombies on dev ports 4200, 7071, or 9876, run\n`scripts/dev-stop.ps1` to free them. `scripts/dev.ps1` also pre-flight checks\nthose ports on launch and tells you to run `dev-stop.ps1` first if any are\nalready in use.\n\n**Manual (any OS):**\n\n```bash\n# Terminal 1 - Functions API on :7071\ncd api\nnpm start              # runs `func start` (prestart = tsc)\n\n# Terminal 2 - Angular SPA on :4200\nnpm start              # ng serve, proxies /api/* to :7071\n```\n\nThen open \u003chttp://localhost:4200\u003e.\n\n**Signing in locally** requires the Entra External ID app registration to\ninclude `http://localhost:4200/` as a redirect URI for both SPA and profile,\nand the matching client/tenant IDs filled into `environment.ts` and\n`api/local.settings.json`. See `infra/README.md` for the one-time manual\nEntra setup steps.\n\n**Custom auth header.** The SPA sends its bearer token as\n`X-Jotjson-Authorization` (Azure Static Web Apps' managed-Functions runtime\nrewrites the standard `Authorization` header; the API reads both but SPA\nclients must use `X-Jotjson-Authorization`). See\n[`DESIGN_SPEC.md` #Auth forwarding](./DESIGN_SPEC.md).\n\n### Debugging in VS Code\n\n`.vscode/launch.json` includes two configs:\n\n- **`ng serve`** - launches Chrome against `http://localhost:4200/` and runs\n  `npm: start` as a preLaunchTask. Set breakpoints in `.ts` files and they\n  bind through the Angular source map.\n- **`ng test`** - launches the Karma debug runner at\n  `http://localhost:9876/debug.html` with `npm: test` as preLaunchTask so you\n  can step through spec execution.\n\nFor the Functions API, run `cd api; npm start` in a terminal and attach\nVS Code's Node debugger to the spawned `func` process (Attach to Node\nProcess), or install the Azure Functions extension and use its \"Attach to\nNode Functions\" config.\n\n### Web (Angular) commands\n\n```bash\nnpm start              # ng serve on http://localhost:4200 (proxies /api/*)\nnpm run build          # production build to dist/jotjson\nnpm run lint           # tsc + ASCII + spec/prod patterns + prettier\nnpm run lint:all       # root lint + api workspace lint (CI-equivalent)\nnpm run lint:ascii     # fail if non-allowlisted non-ASCII sneaks in\nnpm test               # Karma + Jasmine, ChromeHeadless, single run\nnpm run test:ci        # Same, with coverage reporter (CI profile)\n```\n\nTests are co-located as `*.spec.ts`. Run a single spec with\n`npx ng test --include=src/app/path/to/file.spec.ts` or focus interactively\nwith Jasmine's `fdescribe` / `fit`.\n\nCoverage reports land in `coverage/jotjson/` (`index.html` for browse,\n`lcov.info` for tooling).\n\n### API (Azure Functions) commands\n\n```bash\ncd api\nnpm run build          # tsc\nnpm start              # func start on :7071 (runs build via prestart)\nnpm run lint           # tsc --noEmit\nnpm test               # Jest (mocked Cosmos + Blob clients)\n```\n\n`api/local.settings.sample.json` documents required settings - copy to\n`local.settings.json` (gitignored) and fill in real values from Azure.\n\n### Infra (Bicep)\n\nInfrastructure is defined under `infra/` and validated by the `infra.yml`\nworkflow. See [`DESIGN_SPEC.md` #Azure Infrastructure](./DESIGN_SPEC.md)\nand [`infra/README.md`](./infra/README.md) for resource layout and the\none-time Entra app-registration walkthrough.\n\n## CI / CD\n\nThree workflows run on push and PR:\n\n- **CI** (`ci.yml`) - Web build + type-check, API build \u0026 test, Bicep validate, web\n  unit tests with coverage artifact.\n- **CD** (`cd.yml`) - Deploys the web app + managed Functions to Azure Static\n  Web Apps. Gated on `AZURE_STATIC_WEB_APPS_API_TOKEN` being configured.\n- **Infra** (`infra.yml`) - `az deployment group what-if` / apply for Bicep\n  changes. Gated on `vars.AZURE_CLIENT_ID` (OIDC federated credentials).\n\nDependencies are kept current by Dependabot (`.github/dependabot.yml`:\nweekly npm `/`, npm `/api`, and `github-actions`).\n\n## Release history\n\nMilestone boundaries are captured as annotated git tags. List them with\n`git tag -l 'm*-complete'` or view details with `git show m3-complete`:\n\n- **`m1-complete`** - project scaffolding (SPA, Functions, Bicep, CI/CD).\n- **`m2-complete`** - core editor experience (Monaco, tree view, search,\n  theming, PWA, i18n).\n- **`m3-complete`** - Entra External ID sign-in + cloud-synced preferences.\n\n## Contributing\n\nRead [`CONTRIBUTING.md`](./CONTRIBUTING.md) and [`AGENTS.md`](./AGENTS.md)\nbefore opening a PR. Key rules:\n\n- Changes must align with `DESIGN_SPEC.md` (update it in the same PR if\n  behavior or architecture changes).\n- Tests are required for logic changes. `npm run lint`, `npm test`, and\n  `npm run build` must pass before merge (enforced by CI).\n- Strict TypeScript; no `any`. Standalone Angular components, `OnPush`,\n  `inject()`, Signals. Kebab-case filenames.\n- Use `jsonc-parser` - never `JSON.parse` - for user JSON/JSONC input.\n- Tracked source files are ASCII-only (see\n  `scripts/check-ascii.mjs` and `AGENTS.md` #ASCII-only repository).\n- Never log or transmit clipboard/editor contents. No secrets in source.\n\nAI-assisted commits include:\n\n```\nCo-authored-by: Copilot \u003c223556219+Copilot@users.noreply.github.com\u003e\n```\n\n## Security\n\nTo report a security vulnerability, please use GitHub's Private\nVulnerability Reporting rather than a public issue. See\n[`SECURITY.md`](./SECURITY.md) for the policy, scope, and\nresponse-time expectations.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeevensingh%2Fjotjson","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeevensingh%2Fjotjson","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeevensingh%2Fjotjson/lists"}