You are generating a database schema file for LumiDevKit's Database Visualizer. The file you produce will be uploaded to LumiDevKit and may later be pasted into a Bubble.io app. Follow this specification exactly. Important: the parser that reads your output NEVER reports an error for a bad field type. It silently downgrades anything it does not recognise into a meaningless plain value. A wrong string does not fail loudly - it produces a wrong diagram that looks right. Precision matters more than coverage. ==================================================================== 1. OUTPUT CONTRACT ==================================================================== Output exactly ONE fenced ```json code block and nothing else. No preamble, no explanation before or after it, no comments inside the JSON (JSON has no comments), no trailing commas, no markdown headings, no notes. The block contains a single JSON object with exactly these two top-level keys: { "user_types": { ... }, "option_sets": { ... } } - "user_types" is REQUIRED and must be an object. Not null, not an array. - "option_sets" is REQUIRED. If the app has no option sets, emit {} - never omit it. - Add NO other top-level keys. ==================================================================== 2. user_types - the data types (tables) ==================================================================== Each entry: "": { "display": "...", "fields": { ... } } "user_types": { "order": { "display": "Order", "fields": { "reference_text": { "display": "Reference", "value": "text" } } } } Rules: - is the identity of the type. Every link points at this exact string. * lowercase snake_case; letters, digits and underscores only * NEVER contains a dot "."; never contains a space or a capital letter * singular ("order", not "orders") * unique across user_types AND option_sets - never reuse one key in both - "display" is REQUIRED on every user_type. Omit it and the box on the diagram renders with a blank name. Use Title Case: "Order Line Item". - "fields" maps field_key -> { "display": ..., "value": ... } * field_key: lowercase snake_case, unique within its type, no dots * "display" REQUIRED - the human label shown on the diagram * "value" REQUIRED - a string from the closed list in section 4 - Do NOT add id, created_at, created_date, modified_date, creator or slug fields. Bubble creates those automatically; they do not belong in this file. - Do NOT set "deleted": true on anything. Deleted items are hidden from the diagram by default, so the user will think you forgot them. The built-in User type: - Bubble always has a User. Include an entry for it ONLY if your app stores extra fields on the user: "user": { "display": "User", "fields": { ... } } - The key must be exactly "user", lowercase. - If your app adds no user fields, omit the entry entirely. The visualizer draws a built-in User node either way. ==================================================================== 3. option_sets - the fixed choice lists (enums) ==================================================================== "option_sets": { "order_status": { "display": "Order Status", "values": { "pending": { "display": "Pending", "sort_factor": 1 }, "paid": { "display": "Paid", "sort_factor": 2 }, "cancelled": { "display": "Cancelled", "sort_factor": 3 } } } } Rules: - : same naming rules as type keys, and unique across BOTH objects. - "display": Title Case name. Include it. - "values": REQUIRED object. The key is "values" - NOT "options". * each option key: lowercase snake_case * "display": REQUIRED, the label a user sees * "sort_factor": integer controlling order. Number them 1, 2, 3, ... An option with no sort_factor sorts as if it were 0. - Use an option set for any closed list of statuses, categories, roles, tiers or types. Do NOT model a closed list as a separate data type. ==================================================================== 4. THE CLOSED LIST OF "value" STRINGS - this list is exhaustive ==================================================================== A field's "value" MUST be exactly one of the forms below. Lowercase. No spaces. Anything else is silently accepted and silently wrong. SINGLE PLAIN VALUES text free text, emails, URLs, phone numbers, ids, long text number integers, decimals, money, quantities, ratings, counts date a date and time boolean yes / no image an uploaded image file an uploaded non-image file geographic_address a physical address or map location LISTS OF PLAIN VALUES list.text list.number list.date list.boolean list.image list.file (there is NO list.geographic_address) LINK TO ANOTHER DATA TYPE custom. one linked record list.custom. many linked records LINK TO AN OPTION SET option. one chosen option list.option. many chosen options LINK TO THE BUILT-IN USER user one user - this exact bare word list.custom.user many users That is the entire list. Do not invent, abbreviate, or borrow from any other system. These are all WRONG: WRONG USE INSTEAD / WHY list.user list.custom.user <- "list.user" is NOT recognised. It renders as "user[]" on the diagram, so it LOOKS correct, but it draws no link and is not treated as a list. This is the most common failure. Text, TEXT, String, str text (lowercase only) varchar, char, int, integer, float, decimal, bigint, serial, uuid, timestamp, timestamptz, datetime, json, jsonb, array, enum SQL types. Map them onto the list above. yes/no, yesno, bool, checkbox boolean currency, money, price, amount number email, url, link, phone, id, slug text richtext, longtext, textarea text date_range, numeric_range, date_interval Real Bubble types, but LumiDevKit draws them as meaningless plain values. Use date or number, or two separate fields. list.geographic_address geographic_address (lists unsupported) reference, relation, foreign_key, fk, belongs_to, has_many custom. / list.custom. custom.Order custom.order <- keys are case-sensitive custom.orders custom.order <- keys are exact, not plural custom.Order Item custom.order_item <- no spaces option.order.status keys must never contain a dot "value": null, "value": "", or a missing "value" every field needs a real value string ==================================================================== 5. HOW LINKS RESOLVE - read this section twice ==================================================================== "custom.X" and "option.X" are matched against the literal JSON KEY of the target, never against its "display". The match is exact: case-sensitive, whitespace-sensitive, no pluralisation, no fuzzy matching, no normalisation. CORRECT BROKEN "user_types": { "order_item": { ... } } "user_types": { "order_item": {…} } ... "value": "custom.order_item" ... "value": "custom.Order Item" A "custom.X" or "option.X" pointing at a key you never defined does NOT raise an error. It draws a red "[Missing: X]" box on the diagram. Every reference you write must resolve to a key that exists in this same file. "custom." must point at a key inside "user_types". "option." must point at a key inside "option_sets". Crossing them is not detected and produces a wrongly-typed diagram. Directionality: put the link on the side that owns it. An Order that belongs to one Customer gets a "custom.customer" field on Order. Do not also add a "list.custom.order" on Customer unless the app genuinely maintains both sides - duplicated links clutter the diagram without adding information. ==================================================================== 6. WORKED EXAMPLE - this exact file is valid and loads cleanly ==================================================================== { "user_types": { "user": { "display": "User", "fields": { "full_name_text": { "display": "Full Name", "value": "text" }, "avatar_image": { "display": "Avatar", "value": "image" }, "role_option_user_role": { "display": "Role", "value": "option.user_role" } } }, "order": { "display": "Order", "fields": { "reference_text": { "display": "Reference", "value": "text" }, "placed_on_date": { "display": "Placed On", "value": "date" }, "total_number": { "display": "Total", "value": "number" }, "paid_boolean": { "display": "Paid", "value": "boolean" }, "buyer_user": { "display": "Buyer", "value": "user" }, "status_option_order_status": { "display": "Status", "value": "option.order_status" }, "items_list_custom_order_item": { "display": "Items", "value": "list.custom.order_item" }, "watchers_list_custom_user": { "display": "Watchers", "value": "list.custom.user" } } }, "order_item": { "display": "Order Item", "fields": { "product_custom_product": { "display": "Product", "value": "custom.product" }, "quantity_number": { "display": "Quantity", "value": "number" }, "unit_price_number": { "display": "Unit Price", "value": "number" } } }, "product": { "display": "Product", "fields": { "name_text": { "display": "Name", "value": "text" }, "photo_image": { "display": "Photo", "value": "image" }, "price_number": { "display": "Price", "value": "number" }, "tags_list_text": { "display": "Tags", "value": "list.text" } } } }, "option_sets": { "user_role": { "display": "User Role", "values": { "buyer": { "display": "Buyer", "sort_factor": 1 }, "seller": { "display": "Seller", "sort_factor": 2 }, "admin": { "display": "Admin", "sort_factor": 3 } } }, "order_status": { "display": "Order Status", "values": { "draft": { "display": "Draft", "sort_factor": 1 }, "placed": { "display": "Placed", "sort_factor": 2 }, "paid": { "display": "Paid", "sort_factor": 3 }, "shipped": { "display": "Shipped", "sort_factor": 4 }, "cancelled": { "display": "Cancelled", "sort_factor": 5 } } } } } ==================================================================== 7. SELF-CHECK - run every line before you answer ==================================================================== Verify all of the following against the JSON you are about to output. If any check fails, fix the JSON and run the list again. Do not include this checklist, or any report about it, in your answer. 1. The answer is one ```json block and nothing else. 2. JSON.parse would succeed: every key quoted, no comments, no trailing commas. 3. Top-level keys are exactly "user_types" and "option_sets", both present. 4. Every user_type has a non-empty "display". 5. Every field has a non-empty "display" and a non-empty "value". 6. Every "value" is either a literal from the section-4 list, or one of custom. / list.custom. / option. / list.option. followed by a key. Re-read each "value" one at a time. Do not skim. 7. For every "custom.X" and "list.custom.X": X is a literal key of "user_types" in this file, character for character. ("list.custom.user" is always allowed, even if you omitted the "user" entry.) 8. For every "option.X" and "list.option.X": X is a literal key of "option_sets" in this file, character for character. 9. No "custom." points at an option_sets key. No "option." points at a user_types key. 10. The string "list.user" does not appear anywhere. Search for it explicitly. 11. No key anywhere contains a dot, a space, or an uppercase letter. 12. No key is used in both "user_types" and "option_sets". 13. "deleted" does not appear anywhere. 14. No id / created_at / created_date / modified_date / creator / slug fields. 15. Every option set has a "values" object - not "options" - with at least one entry, and every option inside it has a "display". ==================================================================== 8. YOUR TASK ==================================================================== Design the database for the app described below. Include every data type the app needs, the fields on each, the links between them, and every option set. Prefer complete over minimal - this is a starting schema a developer will refine, so it is better to include a plausible field than to leave a gap. APP DESCRIPTION: <<< Replace this line with your app. What does it do? Who uses it? What do they create, browse, buy or submit? What states do things move through? >>>