Owners and admins can point a project at other systems: a signed JSON
POST (HMAC-SHA256 of the body) when tickets, comments, releases or sprints
change, filtered by event or family. Deliveries are retried a couple of
times, the last one is shown, and a ping can be sent from the settings.
Private addresses are refused unless WEBHOOKS_ALLOW_PRIVATE is set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Derived from events and kept per person: whoever a ticket is assigned to,
whoever reports or works on it when it moves, fails QA or gets a comment,
and whoever joins a project. Never about what you did yourself, once per
event. They arrive live through a subscription to a bell in the header,
and are copied by e-mail to whoever turns it on when SMTP_URL is set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Files are uploaded over REST, stored on disk (a volume in Docker) and
recorded on the ticket as events; the bytes are written first, so no
attachment ever points at a missing file. Only images, video, audio, PDF
and plain text are shown inline, everything with nosniff and a sandbox CSP.
The web shows thumbnails, uploads by drag and drop or by pasting a
screenshot, and attaches files to new comments.
Also adds `nx run api:contracts`, which writes schema.gql and
openapi.json without starting the API or any database.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Logs default to warnings and errors (MCP_LOG_LEVEL): the library logged
every tool on every request (~48 lines per call).
- DNS rebinding protection on /mcp, as the MCP spec asks of HTTP servers:
the Host header must be in MCP_ALLOWED_HOSTS (default: localhost; compose
default mcp.taskstream.pireon.dev,localhost) and a browser Origin, when
present, too; otherwise 403 with a JSON-RPC error. Uses the official
validators from @modelcontextprotocol/server.
- Test for allowed/foreign Host and Origin; .env.example, compose and
docs/09-mcp.md document the variables; Word/PDF regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pireon OAuth clients allow a single grant type. With one PIREON_CLIENT_ID of
type password, email + password worked but "Sign in with Pireon" failed with
`unauthorized_client`.
- PIREON_CLIENT_ID/SECRET: authorization_code client (Sign in with Pireon,
Swagger UI). New PIREON_PASSWORD_CLIENT_ID/SECRET: password client, falling
back to the former so existing setups keep working.
- Refresh tries both clients: a refresh token only works with its issuer.
- PIREON_PASSWORD_GRANT=false now also rejects password grants in the API
(before it only hid the form).
- /api/auth/config returns clientId: null when there is no authorization_code
client, and the web hides "Sign in with Pireon".
- docker-compose passes the new variables; docs 05/07, .env.example,
openapi.json; unit tests for the client selection.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A REST adapter next to GraphQL (presenters/http) that calls the same
application services, so validation, permissions and domain errors are the
same: projects (members, board, stats, activity), issues (search, workflow,
assignee, release, links, comments, history), comments, releases and users.
Projects and issues can be addressed by id or key (WEB, WEB-12).
- Swagger UI at /api/docs, document at /api/docs-json and apps/api/openapi.json
(rewritten by `nx serve api`, like schema.gql) for client generation.
- Every route but health/auth/webhook needs a Pireon token: the document
declares Pireon OAuth2 (authorization code + PKCE, password) through the
/api/auth/token proxy, and a bearer scheme for apps with their own client.
- configureApp() shares main.ts setup with the e2e, which now also covers REST.
- SWAGGER_ENABLED / OPENAPI_FILE config; docs 03/05 and library READMEs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dokploy builds failed with "failed to stat /root/.npmrc": the compose build
secret pointed at ${HOME}/.npmrc, which only exists on a developer machine.
The token now comes from the NEXUS_TOKEN environment variable (Dokploy's
Environment tab or .env), is written to a temporary npmrc and removed in the
same RUN, so it never lands in an image layer.
Also removes a temporary UI dev-server spec that was committed by mistake,
and documents the variable (.env.example, docs 06/07, Word/PDF export).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>