## Data persistence The application is using [metaobjects](/docs/apps/build/custom-data#what-are-metaobjects) and a [sqlite](https://www.sqlite.org/) database with [Prisma](https://www.prisma.io/) for data persistence. * Metaobjects are used to store shop-specific data such as application settings. * Prisma is used to store cross-shop data such as billing schedules. ### Metaobjects as shop-specific data persistence Metaobjects are custom data structures that your app can define and create to store your app's information. In the application, metaobjects are used to persist shop-specific data, so to delegate the responsibility of data persistence to Shopify, allowing for a flexible data schema. This approach also allows for robust data access, as the application doesn't need to know about the infrastructure used to persist the data, and Shopify takes care of the scalability and reliability of the data. In the application, metaobject data access is managed using the [MetaobjectRepository](https://github.com/Shopify/subscriptions-reference-app/blob/main/app/utils/metaobjects/MetaobjectRepository.ts#L35). The repository has no knowledge of the metaobject's schema or the application's domain, and only knows how to access the metaobject's data. It can be used to create, read, update, and delete metaobjects of any shapes. Any data access for shop-specific data can easily be found by finding references to the repository. An example of how metaobjects are used in the application is to store the application settings for each shop. To understand how it is used to create the shop specific application settings after authentication, see the [createSettingsMetaobject function](https://github.com/Shopify/subscriptions-reference-app/blob/main/app/models/Settings/Settings.server.ts#L278-L324). The function uses the metaobject repository to create the metaobject for the shop and is responsible for creating its schema. The metaobject repository can also be used to update a metaobject's schema using the [createOrUpdateMetaobjectDefinition function](https://github.com/Shopify/subscriptions-reference-app/blob/ccbfecadfe971697b1affb665649e76b4c5f3407/app/utils/metaobjects/MetaobjectRepository.ts#L426C16-L449). The [EnqueueAddFieldsToMetaobjectJob](https://github.com/Shopify/subscriptions-reference-app/blob/main/app/jobs/migrations/EnqueueAddFieldsToMetaobjectJob.ts) and [AddFieldsToMetaobjectJob](https://github.com/Shopify/subscriptions-reference-app/blob/main/app/jobs/migrations/AddFieldsToMetaobjectJob.ts) are examples of how the function can be leveraged to add new fields in a background job. Metaobjects are a powerful data persistence mechanism that can be used to store any information needed by applications. For more information, see [metaobjects](/docs/apps/build/custom-data#what-are-metaobjects). ## Webhooks The application uses webhooks to handle events from Shopify. Visit the [webhooks documentation](/docs/apps/build/webhooks) to learn more. ## Background jobs This app includes a custom Job Runner to schedule and run background jobs. See the [Job Runner readme](https://github.com/Shopify/subscriptions-reference-app/blob/main/app/lib/jobs/README.md) for more info. By default, this application is configured to use an inline scheduler, but it also comes with a Google Cloud Tasks scheduler. You can opt to use Google Cloud scheduler by changing the `jobs` setting in the `config/index.ts` file. ## Automatic re-billing of subscription contracts In the application, a job scheduler is used to manage and automate the execution of subscription-related tasks on Shopify. For instance, a job is defined to run every hour to find shops that should be billed. Then that job calls [subscriptionBillingCycleBulkCharge](/docs/api/admin-graphql/unstable/mutations/subscriptionBillingCycleBulkCharge) to bill contracts on each shop. The scheduler enqueues the following billing actions: * RecurringBillingChargeJob * RecurringBillingReminderJob * RebillSubscriptionJob These recurring jobs handle billing for subscription contracts. ## Dunning In the application, dunning handles the process of retrying failed billing attempts. When a billing attempt fails, the application checks if it is the final attempt. Based on this, the system decides whether to initiate another billing attempt in the future and notify the buyer via email. If it is the final attempt, the application will notify both the merchant and the buyer via email and update the contracts according to the actions specified in the application settings. <figure class="figure"><img src="https://cdn.shopify.com/shopifycloud/shopify_dev/assets/apps/subscriptions/subscriptions-app-dunning-0c2fbcbac3099bd5d4ea4cc0fec58134a39a525c27a234b9121417d0e73cddca.png" class="lazyload" alt="A diagram showing the dunning flow of the Subscriptions app." width="2788" height="2612"></figure> ## Emails This application is not configured to send customer or merchant emails, but the logic for when to send the emails is in place. You can plug in your own email service to [CustomerSendEmailService](https://github.com/Shopify/subscriptions-reference-app/blob/main/app/services/CustomerSendEmailService.ts) and [MerchantSendEmailService](https://github.com/Shopify/subscriptions-reference-app/blob/main/app/services/MerchantSendEmailService.ts). ## Inventory awareness The app can handle billing attempt failures due to inventory problems. When a billing attempt fails due to inventory, the app displays an error on the billing attempt and notify the merchant. The error can be ignored, and the billing attempt can be retried or skipped. Dunning is also performed as per usual, with the only difference being that it checks the user's inventory settings. The application also has a view specifically designed to display all subscription contracts that have failed due to inventory errors: <figure class="figure"><img src="https://cdn.shopify.com/shopifycloud/shopify_dev/assets/apps/subscriptions/subscriptions-inventory-errors-99da28419dce4dd96cf324391511bbeaa171ffa8c39340412b67cd85566439a6.png" class="lazyload" alt="An image of the subscription contract inventory error view." width="2160" height="1221"></figure> ## Next steps Learn more about [subscription extensions](/docs/apps/build/purchase-options/subscriptions/subscriptions-app/extensions).