Skip to content

Default pdf templates#676

Closed
Mikearaya wants to merge 30 commits intomasterfrom
default-pdf-templates
Closed

Default pdf templates#676
Mikearaya wants to merge 30 commits intomasterfrom
default-pdf-templates

Conversation

@Mikearaya
Copy link
Contributor

No description provided.

@Mikearaya
Copy link
Contributor Author

Mikearaya commented Nov 14, 2025

@pozylon what do you think?
Default order pdf svg template
Importable order PDF that uses react-pdf

and importable google wallet pass

All imprts are with optional dependencies

@Mikearaya Mikearaya requested a review from pozylon November 17, 2025 07:53
@Mikearaya Mikearaya force-pushed the default-pdf-templates branch from ea3fb7b to ac07016 Compare November 17, 2025 08:27
@Mikearaya Mikearaya linked an issue Nov 17, 2025 that may be closed by this pull request
3 tasks
@Mikearaya Mikearaya marked this pull request as ready for review November 17, 2025 09:35
Copy link
Member

@pozylon pozylon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check my comments, there is various topics that needs a bit polishing. After that's done we need to check again how we can make the createPDFTicketRenderer actually useful to create customized tickets.

@Mikearaya Mikearaya force-pushed the default-pdf-templates branch from 459d3fb to 860030e Compare November 19, 2025 12:14
Copy link
Member

@pozylon pozylon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comes together nicely, now we need a factory patter for the pdf ticket renderer so someone can easily set logo, image, colors and such stuff to actually generate tickets that resemble a custom brand.

@Mikearaya Mikearaya force-pushed the default-pdf-templates branch 2 times, most recently from 42b25ec to 820fd08 Compare December 4, 2025 11:01
@Mikearaya Mikearaya requested a review from pozylon December 4, 2025 20:48
@Mikearaya
Copy link
Contributor Author

I haven't tested the apple wallet pass, please do on your end if you can

@Mikearaya Mikearaya force-pushed the default-pdf-templates branch 6 times, most recently from 288bab5 to 517fda9 Compare December 15, 2025 08:56
@pozylon
Copy link
Member

pozylon commented Dec 18, 2025

It's hard to test this functionality as the ticketing example does currently not use the new functions, i'd expect something like this in the ticketing example:

setupTicketing(platform.unchainedAPI as TicketingAPI, {
    renderOrderPDF: createPDFTicketRenderer((orderId: string, context): DefaultTicketProperties => {
      const order = context.modules.orders.getOrderById(orderId);
      const tokens = await modules.warehousing.findTokens({
        "meta.orderId": orderId,
      });
      return {
        title: "Event XY",
        logoUrl: "https://example.com/logo.png",
        orderNumber: orde.orderNumber
        tickets: tokens.map(token => ({
          title: `VIP Ticket: ${token.serialNumber}`,
          qrCode: token.id,
          stripText: `Place: blabla, come early or get the fuck out of here`,
        })),
      }
    }),
  });

renderOrderPDF should be typed to something like this:

createPDFTicketRenderer: (orderId, context) => { contentType: string; blob: ArrayBuffer }

Goal is to give users of the ticketing module a sane default to at least generate usable tickets. If the document generated is unusable it doesn't make sense to give helpers. It should actually print general tickets like in the theater or gastro projects but with a much more generalized design.

User can do:

  1. use the default pdf ticket renderer (no pdf but generateOrderSVG renderer, this should generate svg tickets that are completely unbranded but look like tickets and could be used in a mvp)
  2. configure the ticketing renderer like above to create at least "logo" branded customized tickets
  3. completely re-implement the renderer and take over binary creation

Copy link
Member

@pozylon pozylon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my other comment, although the way you structured it comes together well, the actual "value" for the developer is not leveraged

@Mikearaya Mikearaya force-pushed the default-pdf-templates branch 2 times, most recently from 3cfe981 to edf309b Compare December 29, 2025 14:42
@pozylon pozylon force-pushed the default-pdf-templates branch 2 times, most recently from 15788ec to db21131 Compare January 5, 2026 09:01
@pozylon
Copy link
Member

pozylon commented Jan 5, 2026

@Mikearaya i have rebased this branch on master and did some code cleanups and added default initialization logic to the ticketing example with claude so make sure to hard reset before continuing your work. When done, we should be able to cleanup the Theater im Hof Repository substantially leveraging the factory functions to implement the simple ticket case.

Please make sure the tests pass in the ticketing example and use that to test ticketing stuff. Somehow we need to be able to easily test the processes there so it should seed a product that is a ticket and do some checkout and everything.

@Mikearaya
Copy link
Contributor Author

Added few more tests and fixed existing ones

@Mikearaya Mikearaya force-pushed the default-pdf-templates branch from d291269 to 9b12b50 Compare March 9, 2026 10:17
fastify.route({
url: `${APPLE_WALLET_WEBSERVICE_PATH}*`,
method: ['GET', 'POST', 'DELETE'],
handler: appleWalletHandler,

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.

Copilot Autofix

AI 12 days ago

In general, the fix is to attach rate limiting middleware to the Fastify routes whose handlers perform authorization or other expensive operations. In Fastify applications this is commonly done with the @fastify/rate-limit plugin, which can be configured globally or scoped per-route/per-prefix. To avoid changing existing behavior, we should add a modest, configurable rate limit just to the Apple Wallet webservice routes defined here. This will constrain the number of requests per client IP in a given window while leaving the handlers’ logic, URLs, and methods unchanged.

The best targeted fix within this file is to register the @fastify/rate-limit plugin in a scoped way for the Apple Wallet routes by using fastify.register with a prefix equal to APPLE_WALLET_WEBSERVICE_PATH, and then defining the Apple Wallet route(s) inside that scoped instance with rate-limit options. However, we are constrained to only modify the given snippet and not change imports other than adding well-known packages, and we currently register that route directly on fastify. A minimal and clear approach is:

  • Import @fastify/rate-limit.
  • Register it near the top of the default export with a configuration appropriate for authorization endpoints (for example, 60 requests per minute per IP) and, to avoid affecting unrelated routes unexpectedly, apply the rate limit per-route via route-level config or plugin options.
  • Attach the rate limit specifically to the Apple Wallet route by adding a config property specifying rate-limit settings.

Concretely in packages/ticketing/src/fastify.ts:

  1. Add import rateLimit from '@fastify/rate-limit'; alongside the other imports.
  2. Inside the exported default function, before defining routes, ensure the plugin is registered with the Fastify instance using fastify.register(rateLimit, { global: false }); so that no routes are rate-limited unless explicitly configured.
  3. Update the Apple Wallet route definition to include a config block such as:
    config: {
      rateLimit: {
        max: 60,
        timeWindow: '1 minute',
      },
    }
    This keeps behavior for other routes the same while enforcing a sensible default for authorization-heavy Apple Wallet endpoints.
Suggested changeset 2
packages/ticketing/src/fastify.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/ticketing/src/fastify.ts b/packages/ticketing/src/fastify.ts
--- a/packages/ticketing/src/fastify.ts
+++ b/packages/ticketing/src/fastify.ts
@@ -5,6 +5,7 @@
 import googleWalletHandler from './mobile-tickets/google-handler-fastify.ts';
 import printTicketsHandler from './pdf-tickets/print-handler-fastify.ts';
 import appleWalletHandler from './mobile-tickets/apple-handler-fastify.ts';
+import rateLimit from '@fastify/rate-limit';
 
 export default (fastify: FastifyInstance) => {
   if (ticketingRoutes.length === 0) return;
@@ -14,6 +15,9 @@
     UNCHAINED_PDF_PRINT_HANDLER_PATH = '/rest/print_tickets',
   } = process.env;
 
+  // Register rate limiting plugin with opt-in (non-global) configuration
+  fastify.register(rateLimit, { global: false });
+
   fastify.route({
     url: `${UNCHAINED_PDF_PRINT_HANDLER_PATH}`,
     method: 'GET',
@@ -24,6 +28,12 @@
     url: `${APPLE_WALLET_WEBSERVICE_PATH}*`,
     method: ['GET', 'POST', 'DELETE'],
     handler: appleWalletHandler,
+    config: {
+      rateLimit: {
+        max: 60,
+        timeWindow: '1 minute',
+      },
+    },
   });
 
   fastify.route({
EOF
@@ -5,6 +5,7 @@
import googleWalletHandler from './mobile-tickets/google-handler-fastify.ts';
import printTicketsHandler from './pdf-tickets/print-handler-fastify.ts';
import appleWalletHandler from './mobile-tickets/apple-handler-fastify.ts';
import rateLimit from '@fastify/rate-limit';

export default (fastify: FastifyInstance) => {
if (ticketingRoutes.length === 0) return;
@@ -14,6 +15,9 @@
UNCHAINED_PDF_PRINT_HANDLER_PATH = '/rest/print_tickets',
} = process.env;

// Register rate limiting plugin with opt-in (non-global) configuration
fastify.register(rateLimit, { global: false });

fastify.route({
url: `${UNCHAINED_PDF_PRINT_HANDLER_PATH}`,
method: 'GET',
@@ -24,6 +28,12 @@
url: `${APPLE_WALLET_WEBSERVICE_PATH}*`,
method: ['GET', 'POST', 'DELETE'],
handler: appleWalletHandler,
config: {
rateLimit: {
max: 60,
timeWindow: '1 minute',
},
},
});

fastify.route({
packages/ticketing/package.json
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/packages/ticketing/package.json b/packages/ticketing/package.json
--- a/packages/ticketing/package.json
+++ b/packages/ticketing/package.json
@@ -41,7 +41,8 @@
     "@unchainedshop/core-worker": "^4.6.0",
     "@unchainedshop/events": "^4.6.0",
     "@unchainedshop/logger": "^4.6.0",
-    "@unchainedshop/mongodb": "^4.6.0"
+    "@unchainedshop/mongodb": "^4.6.0",
+    "@fastify/rate-limit": "^10.3.0"
   },
   "peerDependencies": {
     "@parse/node-apn": "^7.0.1",
EOF
@@ -41,7 +41,8 @@
"@unchainedshop/core-worker": "^4.6.0",
"@unchainedshop/events": "^4.6.0",
"@unchainedshop/logger": "^4.6.0",
"@unchainedshop/mongodb": "^4.6.0"
"@unchainedshop/mongodb": "^4.6.0",
"@fastify/rate-limit": "^10.3.0"
},
"peerDependencies": {
"@parse/node-apn": "^7.0.1",
This fix introduces these dependencies
Package Version Security advisories
@fastify/rate-limit (npm) 10.3.0 None
Copilot is powered by AI and may make mistakes. Always verify output.
@Mikearaya
Copy link
Contributor Author

I think this is not needed anymore because it is part of master already

@Mikearaya Mikearaya closed this Mar 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add default PDF templates

2 participants