Skip to content

v1.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 19 Jul 10:57

What's Changed

  • Phase 0: Projektstruktur & Governance by @bigpuritz in #2
  • chore: project governance & tooling (CLA, Renovate, copyright headers, branch-protection ADR) by @bigpuritz in #4
  • docs: correct ADR-0016 — CLA_TOKEN optional, document cla-signatures bootstrap by @bigpuritz in #6
  • feat: bootable Spring Boot server (qnop-app) with PostgreSQL, Liquibase and JPA by @bigpuritz in #24
  • feat: OpenAPI-first REST contract tooling in qnop-api (#9) by @devtank42 in #26
  • feat: security & crypto foundation (SecurityConfig, crypto, QnopProperties) by @devtank42 in #25
  • feat: identity schema (qnop_user, oidc_provider, oidc_identity) by @devtank42 in #27
  • feat: settings schema (application_setting + user_setting + seed) by @devtank42 in #28
  • feat: mail template schema (mail_template + en seed) by @devtank42 in #29
  • feat: application asset schema (application_asset) by @devtank42 in #31
  • feat: token schema (refresh/revoked/email-verification/password-reset) (#12) by @devtank42 in #30
  • feat: application settings service + admin endpoints by @devtank42 in #32
  • feat: JWT & session core (access/refresh tokens, revocation, AuthController) by @devtank42 in #33
  • feat: auth endpoint rate limiting (Bucket4j) by @devtank42 in #34
  • feat: mail subsystem — runtime SMTP, jmustache templates, admin endpoints (#19) by @devtank42 in #35
  • feat: per-user settings service + /users/me/settings by @devtank42 in #37
  • feat: local-user lifecycle core — registration, verification, password reset (Part of #20) by @devtank42 in #38
  • feat: OIDC provider admin + SSRF guard (Part of #21) by @devtank42 in #40
  • feat: OIDC/OAuth2 browser login flow (#21) by @devtank42 in #42
  • feat: branding asset upload, SVG sanitization, public serving by @devtank42 in #41
  • fix: schedule cleanup of expired refresh and revoked tokens by @devtank42 in #51
  • test: cover TokenRevocationService, JwtTokenService and refresh rotation (#44) by @devtank42 in #54
  • fix: harden branding upload — SVG depth limit + I/O outside transaction by @devtank42 in #57
  • perf: index application_setting.updated_by FK (issue #46) by @devtank42 in #58
  • feat: distributed scheduler locks via ShedLock (Postgres-backed) by @devtank42 in #60
  • fix: rate-limit hardening — trusted-proxy warning + bounded bucket cache by @devtank42 in #59
  • fix: uniform ErrorResponse envelope for 401/403/429 + global @ControllerAdvice by @devtank42 in #55
  • feat: optimistic locking for ApplicationSetting by @devtank42 in #56
  • feat: atomic single-use guard for verification/reset tokens (part 2 of #61) by @devtank42 in #63
  • feat: concurrency control for User writes (part 1 of #61) by @devtank42 in #62
  • ci: override Renovate schedule so PRs are actually opened (#64) by @devtank42 in #65
  • chore: phase-1 review code-quality follow-ups (issue #50) by @devtank42 in #66
  • ci: pass App secrets to Renovate via secrets: inherit (#67) by @devtank42 in #68
  • fix: drop invalid comment:schedule key from renovate.json by @devtank42 in #70
  • ci: raise Renovate prHourlyLimit to 10 by @devtank42 in #74
  • chore(deps): pin dependencies by @qnop-renovate[bot] in #72
  • chore(deps): pin dependencies by @qnop-renovate[bot] in #73
  • fix: ignore generated files in Prettier (unblock Renovate npm PRs) (#80) by @devtank42 in #81
  • chore(deps): pin dependencies by @qnop-renovate[bot] in #75
  • fix(deps): pin dependencies by @qnop-renovate[bot] in #79
  • chore(deps): pin dependencies by @qnop-renovate[bot] in #76
  • fix(deps): pin dependencies by @qnop-renovate[bot] in #77
  • fix(deps): update swaggerannotations to v2.2.51 by @qnop-renovate[bot] in #83
  • fix(deps): pin dependencies by @qnop-renovate[bot] in #78
  • chore(deps): update gradle wrapper to v9.6.0 by @qnop-renovate[bot] in #85
  • chore(deps): update npm dependencies to v11.8.0 by @qnop-renovate[bot] in #86
  • fix(deps): update test dependencies by @qnop-renovate[bot] in #84
  • chore(deps): update frontend lint/types tooling by @qnop-renovate[bot] in #82
  • chore(deps): update openapigenerator by @qnop-renovate[bot] in #87
  • fix(deps): update bucket4j by @qnop-renovate[bot] in #88
  • fix(deps): update build tooling to v8.7.0 by @qnop-renovate[bot] in #89
  • fix(deps): update jackson monorepo by @qnop-renovate[bot] in #90
  • fix(deps): update shedlock monorepo to v7.7.0 by @qnop-renovate[bot] in #91
  • chore(deps): update docker base images (major) by @qnop-renovate[bot] in #92
  • chore(deps): update github actions major updates (major) by @qnop-renovate[bot] in #93
  • fix(deps): update test dependencies (major) by @qnop-renovate[bot] in #94
  • chore: guard qnop-ui against non-pnpm installs (#95) by @devtank42 in #96
  • feat: global role model (ADMIN/MEMBER/AUDITOR) + fix admin authority in JWT by @bigpuritz in #107
  • feat: GET /users/me profile endpoint + wire /config self-registration by @bigpuritz in #108
  • chore: auto-load .env in bootRun for local dev by @bigpuritz in #111
  • feat(ui): frontend foundation — routing, react-query, generated API client, auth by @bigpuritz in #109
  • feat(ui): devtank42 design system as MUI theme (Outfit, navy/blue, light+dark) by @bigpuritz in #112
  • feat(ui): app shell — sidebar, top bar, breadcrumbs, role-aware nav by @bigpuritz in #113
  • feat(ui): auth screens — login, register, password reset, email verify, OIDC by @bigpuritz in #114
  • feat: admin user management — /admin/users CRUD + UI (#104) by @bigpuritz in #115
  • feat(ui): auth screen redesign + switch all UI texts to English (#118) by @bigpuritz in #119
  • feat: teams subsystem — entity, /admin/teams CRUD, memberships + UI (#105) by @bigpuritz in #120
  • test: cross-cutting authorization coverage for the Administration surface (#122) by @bigpuritz in #123
  • feat: user-management feature parity — delete, filters/sort, provider name, reset (#124) by @bigpuritz in #125
  • feat(ui): application settings screen + admin menu items (#106) by @devtank42 in #121
  • fix: forced first-login password change — min-length + clear forced-change flag (#128, #130) by @bigpuritz in #129
  • fix(deps): update npm dependencies by @qnop-renovate[bot] in #127
  • chore(deps): update postgres:18 docker digest to 4efc78b by @qnop-renovate[bot] in #134
  • fix(deps): update dependency io.swagger.core.v3:swagger-annotations to v2.2.52 by @qnop-renovate[bot] in #132
  • feat: OIDC end-to-end — provider mgmt, login flow, account lifecycle, Keycloak test setup (#106) by @devtank42 in #126
  • fix(deps): update dependency @mui/material to v9.1.2 by @qnop-renovate[bot] in #137
  • chore(deps): update postgres:18 docker digest to 1a5b3e7 by @qnop-renovate[bot] in #136
  • feat: reset / regenerate a user's password from the UI (#116) by @bigpuritz in #138
  • feat(ui): mail template editor screen (#106) by @devtank42 in #147
  • feat: profile-picture upload (admin + self-service) (#117) by @bigpuritz in #148
  • fix(deps): update npm dependencies by @qnop-renovate[bot] in #131
  • chore(deps): update vite by @qnop-renovate[bot] in #135
  • chore(deps): update actions/setup-java digest to 1bcf9fb by @qnop-renovate[bot] in #151
  • chore(deps): pin quay.io/keycloak/keycloak docker tag to 9b03307 by @qnop-renovate[bot] in #150
  • feat(ui): branding upload screen (#106) by @devtank42 in #149
  • fix(mail): align seeded templates with flow variables; brand HTML via EmailLayoutBuilder (#140) by @devtank42 in #152
  • feat(api): mail-template metadata (placeholders, friendly name, defaults) + validate placeholders (#141) by @devtank42 in #155
  • feat(mail): SMTP config parity — enabled switch, from-name, encryption mode (#142) by @bigpuritz in #156
  • feat(ui): mail templates admin screen — list + editor (#144) by @bigpuritz in #157
  • feat: mail template live preview (sandboxed iframe) + sample variables (#145) by @bigpuritz in #158
  • feat(ui): complete send-test-email affordance in Email/SMTP settings (#146) by @bigpuritz in #159
  • chore: Mailpit SMTP sink in docker-compose for local mail testing (#160) by @bigpuritz in #161
  • feat(ui): render uploaded branding across the app, live on upload (#154) by @bigpuritz in #162
  • test: integration-test suite foundation — testdata SQL seed + first ITs (#163) by @devtank42 in #164
  • test: integration tests for the auth flows (#163) by @devtank42 in #203
  • test: integration tests for admin users and teams (#163) by @devtank42 in #204
  • test: integration tests for settings, OIDC providers and mail templates (#163) by @devtank42 in #205
  • test: integration tests for scheduled cleanup and the error envelope (#163) by @devtank42 in #206
  • ci: smoke-test deployment via docker-compose against testdata (#207) by @devtank42 in #208
  • test(ci): OIDC login smoke test against Keycloak (#225) by @devtank42 in #226
  • fix: validate login response before storing the access token by @devtank42 in #209
  • fix: emit uniform ErrorResponse envelope from PasswordChangeRequiredFilter by @devtank42 in #210
  • fix: revoke AvatarUploader crop-preview object URL on unmount (#171) by @devtank42 in #211
  • fix: give AvatarService.store read-back a diagnosable failure by @devtank42 in #212
  • fix: close encoded open-redirect bypass in safeRedirectPath by @devtank42 in #213
  • chore: enforce a11y linting with eslint-plugin-jsx-a11y (#172) by @devtank42 in #214
  • fix: decouple OIDC post-login redirect from CORS allowed-origins by @devtank42 in #216
  • fix: accessible name for the UsersPage search field (#173) by @devtank42 in #217
  • perf: skip the guaranteed-empty avatar lookup on user creation by @devtank42 in #218
  • fix: re-apply the SSRF policy when (re)building OIDC registrations by @devtank42 in #219
  • fix: enable "strict": true in tsconfig.app.json (#174) by @devtank42 in #220
  • fix: application_asset.uploaded_by FK uses ON DELETE SET NULL by @devtank42 in #221
  • fix: don't leak the constraint property path in the validation 400 by @devtank42 in #222
  • fix: surface OIDC discovery failures instead of swallowing them (#175) by @devtank42 in #223
  • perf: memoize the MUI theme in Root with useMemo by @devtank42 in #224
  • fix(ci): set QNOP_AUTH_OIDC_FRONTEND_BASE_URL in the smoke compose by @devtank42 in #231
  • perf: gate password-change from a JWT claim instead of a per-request DB read by @devtank42 in #215
  • refactor: LAZY fetch for verification/reset token user association (#181) by @devtank42 in #227
  • perf: partial index on refresh_token.family_id (#182) by @devtank42 in #228
  • docs: declare the four missing OpenAPI tags (#183) by @devtank42 in #229
  • fix: OIDC provider duplicate-name returns 409 not 400 (#184) by @devtank42 in #232
  • fix: 409 EXTERNAL_ACCOUNT for change-password on OIDC accounts (#185) by @devtank42 in #233
  • chore(deps): update frontend lint/types tooling by @qnop-renovate[bot] in #133
  • docs: document the io.qnop.security layer in ARCHITECTURE.md by @devtank42 in #234
  • docs: README status badge — Phase 0 → Phase 1 (#197) by @devtank42 in #235
  • docs: note QNOP_AUTH_* secret setup before bootRun in the README by @devtank42 in #236
  • docs: correct the frontend commands in CLAUDE.md by @devtank42 in #237
  • docs(adr): document-review core architecture (#239) by @bigpuritz in #240
  • docs(adr): e-signature approval as a post-finalization enterprise feature (#253) by @bigpuritz in #255
  • docs: refresh CLAUDE.md current-state + module diagram (#198) by @devtank42 in #238
  • fix(deps): pin dependencies by @qnop-renovate[bot] in #256
  • fix(deps): update npm dependencies by @qnop-renovate[bot] in #258
  • chore(deps): update docker base images by @qnop-renovate[bot] in #259
  • chore(deps): update dependency vite to v8.1.2 by @qnop-renovate[bot] in #257
  • fix(deps): pin dependencies by @qnop-renovate[bot] in #260
  • chore(deps): update quay.io/keycloak/keycloak:26.6 docker digest to 0aae0de by @qnop-renovate[bot] in #261
  • chore(deps): update gradle to v9.6.1 by @qnop-renovate[bot] in #262
  • build: align Renovate minimumReleaseAge with pnpm 11 supply-chain karenz (#264) by @bigpuritz in #265
  • build: align openapi-generator versions and group them in Renovate by @devtank42 in #266
  • test: cover PasswordChangeRequiredFilter enforcement (#189) by @devtank42 in #268
  • fix: align displayName maxLength to VARCHAR(255) across schemas by @devtank42 in #269
  • build: pin the Gradle distribution checksum (distributionSha256Sum) by @devtank42 in #270
  • test: PasswordResetTokenServiceTest for consume() guard branches (#190) by @devtank42 in #271
  • test: OidcLoginService provider-resolution branches (#191) by @devtank42 in #272
  • fix: add format:uri and maxLength to OIDC URI fields in the contract by @devtank42 in #273
  • test: cover UserService self-registration, existence and password-reset paths by @devtank42 in #274
  • ci: per-PR dependency vulnerability audit gates (frontend pnpm audit + backend OWASP) by @devtank42 in #275
  • test: add controller-level IT for the public auth flows by @devtank42 in #276
  • build: enforce SPDX headers on Kotlin DSL files via Spotless by @devtank42 in #277
  • fix: replace invalid Renovate // comment key with description (#267) by @devtank42 in #279
  • chore: run integration tests on postgres:18 to match local/prod infra by @devtank42 in #278
  • feat(core): durable async job queue on Postgres (#242) by @bigpuritz in #280
  • feat(core): document-review domain model + schema (#244) by @bigpuritz in #281
  • feat(core): StorageProvider SPI + S3/MinIO adapter (ADR-0005, #243) by @devtank42 in #282
  • feat(core): review workflow state machine (ADR-0011) by @devtank42 in #283
  • feat(core): document ingest, PDF extraction & serving (ADR-0032/0010) by @devtank42 in #284
  • feat(core): annotations, comments & placements API (ADR-0009/0011, #247) by @devtank42 in #285
  • feat(core): inter-version diff (ADR-0034, #249) by @devtank42 in #286
  • feat(core): async re-anchoring engine (ADR-0009) by @devtank42 in #288
  • feat(ui): document viewer + annotation layer (ADR-0032/0009) by @bigpuritz in #287
  • feat(core): document listing, participants & principal directory API (#292) by @bigpuritz in #293
  • feat(ui): reviews surface — overview, wizard, hub head & decisions (#251) by @bigpuritz in #294
  • fix(core): stop interleaving characters of overlapping text runs (#296) by @bigpuritz in #297
  • feat(core): glyph-true per-character span geometry & pointer selection (#290) by @bigpuritz in #299
  • feat: make the annotation's first comment mandatory (#301) — re-land on main by @bigpuritz in #303
  • feat: optional review due date (Community) (#295) by @devtank42 in #304
  • feat(ui): version diff view with located change highlights (#252) by @bigpuritz in #305
  • fix(ui): keep the review viewer polling after a new-version upload (#300) by @devtank42 in #350
  • fix(core): dedup only COMMITTED storage rows; re-upload poisoned PENDING keys by @devtank42 in #310
  • test: extend smoke test to cover object storage + review pipeline (#308) by @devtank42 in #309
  • test: prove OIDC state is validated end-to-end (issue #321) by @devtank42 in #353
  • fix(core): cap PDF page count to bound extraction DoS (issue #322) by @devtank42 in #356
  • fix: authorize workflow status reads and drop entity leak from web (#311, #315) by @devtank42 in #355
  • perf: resolve document access in a single query (#312) by @devtank42 in #358
  • test(ui): cover the login flow (#317) by @devtank42 in #354
  • perf: run extraction I/O outside the DB transaction and stream large PDFs (#314) by @devtank42 in #362
  • perf: batch placements and comment counts in annotation list (#313) by @devtank42 in #360
  • fix(core): require a READY version to finalize a review (issue #323) by @devtank42 in #357
  • docs(api): reference the 429 response on rate-limited endpoints (#347) by @devtank42 in #364
  • perf: stream document uploads instead of materializing them in the heap (#361) by @devtank42 in #365
  • test(app): guard @Valid on every generated request body (#346) by @devtank42 in #367
  • feat(ui): focus view mode — spotlight overlay for annotations (#291) by @bigpuritz in #363
  • fix(ui): replace unsafe viewer casts and non-null assertions (#335) by @devtank42 in #366
  • fix: explicit servlet + HTTP client timeouts (#342) by @devtank42 in #368
  • test: exercise the multi-version document fixtures in IT and smoke (#370) by @bigpuritz in #371
  • docs(api): document 401 on authenticated review-domain endpoints (#327) by @devtank42 in #372
  • fix(api): use the framework ObjectMapper in AnnotationController (#329) by @devtank42 in #373
  • perf: index the review/diff foreign-key columns (#330) by @devtank42 in #374
  • fix(ui): error boundaries around viewer/panel + lazy routes (#331) by @devtank42 in #376
  • refactor: split JobEnqueuer out of JobService to break the handler cycle (#318) by @devtank42 in #377
  • refactor: handle xlink:href explicitly in the SVG sanitizer (#338) by @devtank42 in #378
  • fix(core): guard getInteger against missing/blank setting values (#340) by @devtank42 in #380
  • fix: validate the S3 storage key format before use (#337) by @devtank42 in #381
  • fix: give the viewer text layer an accessible label (#341) by @devtank42 in #382
  • refactor: typed job-payload (de)serialization via a shared codec (#319) by @devtank42 in #383
  • feat: annotations and decisions on the latest version only (#306) by @bigpuritz in #379
  • feat: word-accurate diff boxes, collapsible changes rail, card radius by @bigpuritz in #384
  • fix(core): persist OidcProviderService.update() with an explicit save (#339) by @devtank42 in #385
  • fix(ui): stable diff-list keys and memoized annotation derivations (#334) by @devtank42 in #387
  • fix: derive download filename extension from the content type (#328) by @devtank42 in #388
  • docs: document accepted upload formats + fix supportedFormats (#345) by @devtank42 in #386
  • perf: memoize annotation panel rows to cut re-render overhead (#333) by @devtank42 in #390
  • perf(ui): fetch the PDF eagerly from an explicit ?version= (#332) by @devtank42 in #391
  • refactor: modernise the re-anchoring core (AnchorResolver) (#320) by @devtank42 in #389
  • feat(core): optional annotation classification — type & priority by @bigpuritz in #396
  • feat: tasks view — annotations as a kanban board and task list by @bigpuritz in #397
  • feat: prominent labeled view tabs for Document / Focus / Tasks / Compare by @bigpuritz in #399
  • feat: unseen markers since the participant's last visit by @bigpuritz in #400
  • chore: expand the shared test seed — 20-user crowd, 5 teams, Mailpit SMTP by @bigpuritz in #402
  • fix: review surfaces — polish & bugfix round (#403) by @bigpuritz in #404
  • feat: author-only resolve & annotation-driven workflow (#405) by @bigpuritz in #406
  • fix: review UI polish round 2 (#403) by @bigpuritz in #409
  • fix: review UI polish round 3 (#403) by @bigpuritz in #414
  • feat: review slug URLs & new-review wizard polish (#411, #415) by @bigpuritz in #416
  • fix(compose): mount the local Postgres volume at /var/lib/postgresql (#407) by @devtank42 in #417
  • feat(platform): observability — job-queue health indicator + Prometheus metrics (#348) by @devtank42 in #418
  • feat: per-review anonymity — server-resolved author names & Participant N (#413 pt.1) by @bigpuritz in #419
  • feat: thread participation policy — PRIVATE/READ_ONLY/OPEN (#413 pt.2, re-targeted to main) by @bigpuritz in #424
  • fix(security): list explicit CORS allowed-headers instead of "*" (#336) by @devtank42 in #425
  • fix: hide the reviewer roster from non-owners in anonymous reviews + anonymity marker (#422) by @bigpuritz in #426
  • feat(reviews): permalinks for annotations and comments (#412) by @bigpuritz in #428
  • feat(reviews): document-scoped (global) annotations without a text anchor (#395) by @bigpuritz in #429
  • test(core): AnchorResolver re-anchoring boundary edge cases (#351) by @devtank42 in #430
  • fix(core): contain the version-diff cache race in its own transaction (#351) by @devtank42 in #431
  • test(review): concurrency, extraction-failure cascade & annotation-decision authz ITs (#351) by @devtank42 in #435
  • test(ui): auth-flow coverage — wave 1 of #352 by @devtank42 in #434
  • test(core): service-layer authorization & logic suites (#349) by @devtank42 in #433
  • test(ui): document-viewer coverage — wave 2 of #352 by @devtank42 in #436
  • test(ui): admin-surface coverage — wave 3 of #352 by @devtank42 in #442
  • fix(deps): update npm dependencies by @qnop-renovate[bot] in #441
  • chore(deps): update dependency vite to v8.1.3 by @qnop-renovate[bot] in #440
  • fix(deps): update dependency react-easy-crop to v6.2.0 by @qnop-renovate[bot] in #444
  • feat(reviews): render Markdown in annotation & comment bodies (#427) by @bigpuritz in #432
  • feat(reviews): Slack-style discussion UI & comment attachments (#445, #446) by @bigpuritz in #447
  • feat(reviews): deliver Slack-style discussion UI & comment attachments to main (#445, #446) by @bigpuritz in #448
  • feat(reviews): Document/Focus tab merge & focus-view polish round (#403) by @bigpuritz in #449
  • docs: tighten working rules — Conventional Commits always, push needs approval (#450) by @bigpuritz in #451
  • feat(reviews): task drawer head, resizable drawers & full-screen writing stage (#403) by @bigpuritz in #452
  • feat(reviews): Slack-style emoji reactions on annotations and comments (#410) by @bigpuritz in #453
  • feat(dashboard): the review command centre (#454) by @bigpuritz in #455
  • feat(theme): black-based neutral dark mode, derived greyscale ramp (#423) by @bigpuritz in #456
  • feat(reviews): re-attach orphaned annotations by selecting a new passage by @bigpuritz in #459
  • feat(reviews): audit extraction outcomes and persist the failure reason (#325) by @devtank42 in #463
  • chore(deps): update docker base images by @qnop-renovate[bot] in #439
  • chore(deps): update actions/setup-java digest to 0f481fc by @qnop-renovate[bot] in #438
  • feat(reviews): email notifications on review events by @bigpuritz in #467
  • feat(build): Liquibase seam for enterprise-module schema by @bigpuritz in #468
  • feat(ui): gamification polish round — launch pad, wizard, player card, avatars everywhere by @bigpuritz in #474
  • feat(reviews): copy to clipboard — viewer selection, quotes & comments by @bigpuritz in #483
  • feat(reviews): one flat annotation list with per-card scope markers by @bigpuritz in #484
  • feat(users): public profile as a player card — stats, achievements, teams by @bigpuritz in #485
  • feat(users): readable profile URLs via an immutable user slug by @bigpuritz in #487
  • feat(users): profile hover card (player card) with a hard anonymity gate by @bigpuritz in #489
  • fix(reviews): resolve the owner's name on the document, not the directory by @bigpuritz in #490
  • fix(reviews): mark clicks glide the panel to their annotation by @bigpuritz in #492
  • chore(deps): update dependency vite to v8.1.4 by @qnop-renovate[bot] in #476
  • docs: prune all documentation to the current state by @bigpuritz in #499
  • feat(release): Docker release pipeline, SPA embedding and snapshot publishing (ADR-0040) by @bigpuritz in #500
  • feat: real qnop brand assets (logomark, wordmark, favicon, og-image) by @bigpuritz in #501
  • docs(release): the encryption salt must be hex-encoded by @bigpuritz in #502
  • fix(deps): update npm dependencies by @qnop-renovate[bot] in #477
  • feat(auth): redesign the auth pages and polish the dashboard (#503) by @bigpuritz in #504
  • feat: L10n — UTC storage, ISO-offset API timestamps, user-timezone display (#465) by @devtank42 in #507
  • feat(reviews): role-gated audit UI over the document audit trail (#466) by @devtank42 in #506
  • feat(teams): let team leads self-manage their own teams (#470) by @devtank42 in #505
  • feat(auth): review-focused showcase and brand-aligned imagery colors by @bigpuritz in #512
  • chore(ui): shell cleanup — drop the Compliance placeholder, reorder admin nav, honest coming-soon triggers by @bigpuritz in #515
  • docs: user-facing README and Docker Hub description for the first release by @bigpuritz in #517
  • fix(release): replace two unresolvable action SHA pins by @bigpuritz in #519

New Contributors

  • @qnop-renovate[bot] made their first contribution in #72

Full Changelog: https://github.com/qnophq/qnop/commits/v1.0.0