Complete Persistent Inventory with Secure DataStore
Generate a professional inventory persistence system for Roblox, capable of saving and loading items with ID, quantity, and rarity across sessions. The prompt instructs the AI to respect the architecture already in place in your game, using the real names of folders, RemoteEvents, modules, and objects you provide.
The requested solution prioritizes security and reliability: the server is authoritative, data coming from the client is validated, the DataStore is accessed with failure protection, and saving happens at appropriate moments, including player exit and server shutdown. Ideal for RPGs, simulators, collection games, survival games, and loot-based experiences.
In addition to the full, commented code, the prompt requires clear instructions for installation, configuration, and testing in Roblox Studio, so the result can be adapted and pasted directly into the project.
Act as a senior Roblox developer, specialized in Luau, DataStoreService, server-authoritative architecture, and persistent inventory systems. Develop a complete, robust, and secure system to save and load player inventories, preserving item, quantity, and rarity across sessions. Before writing the code, consider and use the context below. If any field is empty, adopt professional conventions, explicitly state any assumptions made, and keep the implementation easy to adapt: [PASTE HERE THE CONTEXT OF MY GAME] - Where the current inventory is stored: (e.g., Folder in Player, attributes, table in ModuleScript, custom system) - Structure of each item: (e.g., ItemId, Amount/Quantity, Rarity/Raridade, other metadata) - Official list/catalog of items and rarities: (path in Explorer or description) - Real names and paths in Explorer: (folders, modules, existing RemoteEvents/RemoteFunctions) - RemoteEvents/RemoteFunctions already used by the inventory and their signatures: - UI format, if any, and how it is updated: - Slot limit, maximum quantity per item, and stacking rules: - Items that cannot be saved, starter items, and data migration rules: - Desired DataStore name and current version/schema, if any: - Other systems that modify the inventory (store, loot, trade, crafting, reward, etc.): [END OF CONTEXT] Deliver a production-architecture solution made up of: 1) a ModuleScript called InventoryService, located in ServerScriptService/Modules/InventoryService; and 2) a Script called InventoryPersistence.server.lua, located in ServerScriptService. If integration with an existing interface requires synchronization, include only the strictly necessary RemoteEvents in ReplicatedStorage/Remotes, describing how to create them. Do not let the client save, grant, remove, set rarity, or validate items; all inventory and persistence authority must remain on the server. The system must use DataStoreService with a versioned name, such as InventoryData_v1, and keys based on UserId. Define a serializable schema, with no Instances, functions, userdata, or tables with invalid keys. Each item entry must contain, at minimum, itemId (string), amount (positive integer number), and rarity (string). Include schemaVersion and, if appropriate, safe metadata fields. Create a normalization and validation function for loaded data: discard malformed records, cap quantities according to the provided rules, validate itemId against the official server-side catalog, and validate rarity against allowed values or against the item’s official rarity. Never accept a rarity, ID, or quantity sent by the client without independent server-side validation. Implement clear server-side APIs in the module, such as LoadInventory(player), GetInventory(player), AddItem(player, itemId, amount, optionalRarity), RemoveItem(player, itemId, amount), SaveInventory(player), and ClearCache(player). Protect operations against race conditions using a per-player lock or save queue. When saving, use UpdateAsync instead of SetAsync when appropriate, pcall, retries with moderate exponential backoff, and detailed warn messages without exposing sensitive data. Avoid exceeding request limits: use autosave with a configurable interval and do not save on every individual change. Track changes with a dirty flag; save on PlayerRemoving and handle BindToClose while waiting, within a reasonable limit, for pending saves. If RemoteEvents are needed for the UI, treat them only as read requests or allowed actions. Validate the type, size, rate of calls, and permissions of received arguments on the server. Do not implement a RemoteEvent that accepts a full inventory table from the client to save. If the project already has remotes in the context, adapt to them instead of creating duplicates. Return to the client only a sanitized copy of the data needed for display. Provide the result in Brazilian Portuguese, with no pseudocode and without omitting essential parts. Organize the response in this order: architecture overview; exact object tree in Explorer; full code for each file, each in its own markdown ```lua block, with a header stating type and location; integration steps with the existing inventory; and a testing guide in Roblox Studio. The code must be complete, syntactically valid in Luau, and extensively commented, including comments on security, schema, retries, cache, dirty flag, and server shutdown. At the end, explain how to enable API Services to test DataStore in Studio, how to test with Start Server/Start Player, how to verify persistence across sessions, and how to simulate DataStore failures without corrupting the inventory.