···442442443443</Tabs>
444444445445+## Database
446446+447447+Multi-scrobbler depends on a SQLite database (`ms.db`) that is created on first run and stored in the [`CONFIG_DIR`](/installation/?dockerSetting=storage#recommended-settings). When upgrading Multi-scrobbler version, if there are any required database changes than this database is [automatically backed up and migrated.](/updating#database)
448448+449449+The database stores *all* Plays for your Sources/Clients as well as metadata and debugging information to help troubleshoot issues. Each Play is associated with a Source/Config in the database based on your configuration.
450450+451451+You **should set IDs for each Source/Client** so that the database can identify these even when the configuration is changed.
452452+453453+### Retention
454454+455455+<DetailsAdmo status="note" summary="How much storage does the database use?">
456456+457457+The amount of data stored for each Play can widely vary based on a few factors:
458458+459459+* how much data the Source service exposes
460460+* how many clients each Source is scrobble to (Plays are duplicated for each Client a Source sends a scrobble to)
461461+* if you are using any [Transforms](/configuration/transforms) the diff of each step is stored, along with any external request/response data (like [Musicbrainz queries](/configuration/transforms/musicbrainz))
462462+463463+The [MS repository contains a benchmark](https://github.com/FoxxMD/multi-scrobbler/blob/master/src/backend/tests/database/drizzle.test.ts#L551) to measure an average database size in a few common scenarios.
464464+465465+<Tabs groupId="dbSize">
466466+467467+<TabItem label="Minimal" value="minimal">
468468+469469+Assuming your Sources send a minimal amount of data or you have compacted all plays:
470470+471471+| Play Count | DB Size |
472472+| ---------- | -------- |
473473+| 100 | `160kb` |
474474+| 1000 | `1MB` |
475475+| 10k | `10.2MB` |
476476+477477+</TabItem>
478478+479479+<TabItem label="With Original Input" value="input">
480480+481481+Assuming your Sources have a non-trivial amount of input data (like Spotify or Listenbrainz) that is not compacted:
482482+483483+| Play Count | DB Size |
484484+| ---------- | -------- |
485485+| 100 | `356kb` |
486486+| 1000 | `3MB` |
487487+| 10k | `29.6MB` |
488488+489489+</TabItem>
490490+491491+<TabItem label="All Debug Deta" value="all">
492492+493493+Assuming your Sources/Clients:
494494+495495+* have a non-trivial amount of input data (like Spotify or Listenbrainz)
496496+* and has many [Transforms](/configuration/transforms) steps that include requests
497497+* nothing is compacted
498498+499499+| Play Count | DB Size |
500500+| ---------- | -------- |
501501+| 100 | `684kb` |
502502+| 1000 | `6.28MB` |
503503+| 10k | `61.3MB` |
504504+505505+</TabItem>
506506+507507+</Tabs>
508508+509509+</DetailsAdmo>
510510+511511+A retention policy can be configured to delete Plays, or unused debug data, from the database after a certain amount of time. If no configuration is provided then a default policy is used that should be reasonable for most users.
512512+513513+<Tabs groupId="policy" queryString>
514514+515515+<TabItem label="Compaction" value="compaction">
516516+517517+The **Compaction** Retention Policy is used to delete different types of debug data from your stored Plays.
518518+519519+This is a useful way to reduce used storage space when you are not having problems with your Plays, or iterating on a configuration, that requires referencing all this extra data.
520520+521521+There are two types of data that can be compacted (deleted from the Play):
522522+523523+* `input` - this is the untouched data retrieved by Multi-scrobbler, from a Source, and used to generate a Play/scrobble. This can be used to reconstruct and replay a Play, when used from troubleshooting or reporting an issue
524524+* `transform` - this is all of the steps generated by [transforms](/configuration/transforms), the diff of the Play resulting from the step, and any request/responses used to complete the step
525525+526526+:::note[Defaults]
527527+528528+When no Compact configuration is provided, Multi-scrobbler uses this policy:
529529+530530+* Compact (delete) `input` and `transform` data on all Plays after 3 days
531531+532532+:::
533533+534534+#### Configuring Compaction Policy
535535+536536+<details>
537537+538538+<summary>Details</summary>
539539+540540+Each value in the configuration properties below can be either
541541+542542+* a number of seconds EX `3600` = 10 minutes
543543+* a unit of a common duration with the pattern `X unit` EX
544544+ * `30 minutes`
545545+ * `5 hours`
546546+ * `2 days`
547547+548548+<Tabs groupId="configType" queryString>
549549+550550+<TabItem value="env" label="ENV">
551551+552552+* `COMPACT_PROPERTIES` - which properties to compact
553553+* `RETENTION_COMPACT_AFTER` - Default to use for all Plays
554554+* `RETENTION_COMPACT_COMPLETED_AFTER` - Compact only completed Plays after...
555555+* `RETENTION_COMPACT_FAILED_AFTER` - Compact only failed Plays after...
556556+* `RETENTION_COMPACT_DUPED_AFTER` - Compact only duped/discard Plays after...
557557+558558+Example
559559+560560+```ini
561561+# only delete input when compacting
562562+COMPACT_PROPERTIES=input
563563+# compact all plays after 3 days
564564+RETENTION_COMPACT_AFTER=3 days
565565+# specifically compact completed plays after 30 minutes
566566+RETENTION_COMPACT_COMPLETED_AFTER=30 minutes
567567+```
568568+569569+</TabItem>
570570+<TabItem value="aio" label="AIO">
571571+572572+Compacting all Play types and deleting both input and transform:
573573+574574+```json title="config.json"
575575+{
576576+ "database": {
577577+ "retention": {
578578+ "compactAfter": "3 days",
579579+ "compact": [
580580+ "input",
581581+ "transform"
582582+ ]
583583+ }
584584+ }
585585+}
586586+```
587587+588588+* Delete only input during compacting
589589+* Compact all after 3 days except completed which compacts after 30 minutes
590590+591591+```json title="config.json"
592592+{
593593+ "database": {
594594+ "retention": {
595595+ "compactAfter": {
596596+ "completed": "30 minutes",
597597+ "duped": "3 days",
598598+ "failed": "3 days"
599599+ },
600600+ "compact": [
601601+ "input"
602602+ ]
603603+ }
604604+ }
605605+}
606606+```
607607+608608+</TabItem>
609609+</Tabs>
610610+611611+</details>
612612+613613+</TabItem>
614614+615615+<TabItem label="Deletion" value="deletion">
616616+617617+The **Deletion** Retention Policy is used to delete different types of stored Plays from Multi-scrobbler database.
618618+619619+**This does not delete Plays from your Clients.** It's only deleting the "in-flight" data MS used to create the scrobble that was eventually sent to your clients.
620620+621621+:::warning[Plays Should be Ephemeral]
622622+623623+**Multi-Scrobbler is not designed to store Plays/Scrobbles indefinitely.**
624624+625625+It should scale fine for thousands of scrobbles but it not meant to store 10's of thousands of scrobbles forever. It is not a scrobbler server.
626626+627627+You **should** set a reasonable deletion policy so that MS stores less than 1000 scrobbles at a time, ideally less.
628628+629629+:::
630630+631631+:::note[Defaults]
632632+633633+When no Deletion policy configuration is provided, Multi-scrobbler uses this policy:
634634+635635+* Delete all Plays after 7 days
636636+637637+:::
638638+639639+#### Configuring Deletion Policy
640640+641641+<details>
642642+643643+<summary>Details</summary>
644644+645645+Each value in the configuration properties below can be either
646646+647647+* a number of seconds EX `3600` = 10 minutes
648648+* a unit of a common duration with the pattern `X unit` EX
649649+ * `30 minutes`
650650+ * `5 hours`
651651+ * `2 days`
652652+653653+<Tabs groupId="configType" queryString>
654654+655655+<TabItem value="env" label="ENV">
656656+657657+* `RETENTION_DELETE_AFTER` - Default to use for all Plays
658658+* `RETENTION_DELETE_COMPLETED_AFTER` - Delete only completed Plays after...
659659+* `RETENTION_DELETE_FAILED_AFTER` - Delete only failed Plays after...
660660+* `RETENTION_DELETE_DUPED_AFTER` - Delete only duped/discard Plays after...
661661+662662+Example
663663+664664+```ini
665665+# delete all plays after 3 days
666666+RETENTION_DELETE_AFTER=3 days
667667+# specifically, delete completed plays after 30 minutes
668668+RETENTIOND_DELETE_COMPLETED_AFTER=30 minutes
669669+```
670670+671671+</TabItem>
672672+<TabItem value="aio" label="AIO">
673673+674674+Deleting all Play types after 3 days:
675675+676676+```json title="config.json"
677677+{
678678+ "database": {
679679+ "retention": {
680680+ "deleteAfter": "3 days"
681681+ }
682682+ }
683683+}
684684+```
685685+686686+* Delete all after 3 days except completed which are deleted after 30 minutes
687687+688688+```json title="config.json"
689689+{
690690+ "database": {
691691+ "retention": {
692692+ "deleteAfter": {
693693+ "completed": "30 minutes",
694694+ "duped": "3 days",
695695+ "failed": "3 days"
696696+ },
697697+ }
698698+ }
699699+}
700700+```
701701+702702+</TabItem>
703703+</Tabs>
704704+705705+</details>
706706+707707+</TabItem>
708708+709709+710710+</Tabs>
711711+445712## Debug Mode
446713447714Turning on Debug Mode will
+1-1
src/backend/common/AbstractComponent.ts
···5858 super(config);
5959 this.transformManager = config.transformManager ?? getRoot().items.transformerManager;
6060 this.cache = getRoot().items.cache();
6161- const cProps = config.options?.retention?.compact ?? parseArrayFromMaybeString(process.env.COMPACT_PROPERTIES, {lower: true});
6161+ const cProps = config.options?.retention?.compact ?? parseArrayFromMaybeString(process.env.COMPACT_PROPERTIES ?? 'input,transform', {lower: true});
6262 if(!cProps.every(isCompactableProperty)) {
6363 throw new SimpleError(`Compactable properties must be one of 'transform' or 'input'. Given: ${cProps.join(',')}`);
6464 }