{
  "name": "Cortado",
  "slug": "cortado",
  "blocks": ["Pages", "Lists", "Sign-in: users", "Actions: pay, scan"],
  "persona": "hospitality",
  "keywords": [
    "order ahead",
    "coffee shop app",
    "café app",
    "pre-order",
    "click and collect",
    "coffee pass",
    "order and pay",
    "regulars",
    "loyalty",
    "QR",
    "order coffee app",
    "pickup time",
    "stamp card",
    "member sign-in",
    "commuter coffee"
  ],
  "description": "An app template: a coffee counter's own order-ahead and loyalty app. Regulars sign in with their email, order a drink for a pickup time from 07:30 to 11:00 and follow it from Received to Ready, collect by name, and show a code at the counter for a stamp; nine stamps earn a free drink. They pay at the counter or join a £30 Coffee pass. Staff scan the code and confirm. A public page, six member screens under /app (Home, Order, Orders, Card, Rewards, Account) and a privacy notice with blanks.",
  "audience": [
    "coffee shops and counters by a station",
    "cafés with commuter regulars",
    "takeaway coffee and tea bars"
  ],
  "category": "Customer requests",
  "job": "member-app",
  "categoryId": "requests",
  "alsoFits": [
    "order ahead",
    "click and collect",
    "pickup orders",
    "coffee loyalty",
    "takeaway counter",
    "pre-order menu"
  ],
  "direction": "Station café app: a departures board for your order, a red platform sign and a paper stamp card with red ink stamps",
  "mood": [
    "dark",
    "bold",
    "modern"
  ],
  "fonts": [
    "Big Shoulders Display",
    "Figtree"
  ],
  "memberApp": {
    "path": "/app",
    "setup": {
      "signup": "open",
      "profile_fields": [
        {
          "name": "name",
          "type": "text",
          "label": "First name",
          "required": true
        }
      ],
      "display_field": "name"
    },
    "lists": [
      {
        "list": "orders",
        "label": "Orders",
        "by": "member",
        "fields": [
          {
            "name": "drink",
            "type": "choice",
            "label": "Drink",
            "required": true,
            "options": [
              "Flat white",
              "Cortado",
              "Latte",
              "Cappuccino",
              "Americano",
              "Filter",
              "Chai latte",
              "Hot chocolate"
            ]
          },
          {
            "name": "size",
            "type": "choice",
            "label": "Size",
            "required": true,
            "options": [
              "Small",
              "Regular"
            ]
          },
          {
            "name": "milk",
            "type": "choice",
            "label": "Milk",
            "required": true,
            "options": [
              "Whole",
              "Oat",
              "Skimmed",
              "No milk"
            ]
          },
          {
            "name": "extra",
            "type": "text",
            "label": "Extras or changes"
          },
          {
            "name": "pickup_date",
            "type": "date",
            "label": "Pickup day",
            "required": true
          },
          {
            "name": "pickup",
            "type": "choice",
            "label": "Pickup time",
            "required": true,
            "options": [
              "07:30",
              "07:40",
              "07:50",
              "08:00",
              "08:10",
              "08:20",
              "08:30",
              "08:40",
              "08:50",
              "09:00",
              "09:10",
              "09:20",
              "09:30",
              "09:40",
              "09:50",
              "10:00",
              "10:10",
              "10:20",
              "10:30",
              "10:40",
              "10:50",
              "11:00"
            ]
          },
          {
            "name": "cup_name",
            "type": "text",
            "label": "Name on the cup"
          }
        ],
        "status_options": [
          "Received",
          "Being made",
          "Ready",
          "Collected",
          "Cancelled"
        ]
      },
      {
        "list": "stamps",
        "label": "Stamps",
        "by": "owner",
        "fields": [
          {
            "name": "item",
            "type": "text",
            "label": "For",
            "required": true
          }
        ]
      },
      {
        "list": "passes",
        "label": "Coffee pass redemptions",
        "by": "owner",
        "fields": [
          {
            "name": "item",
            "type": "text",
            "label": "For",
            "required": true
          }
        ]
      }
    ],
    "scan": [
      {
        "list": "stamps",
        "actions": [
          {
            "label": "Stamp",
            "values": {
              "item": "Order collected"
            },
            "goal": 9,
            "daily_limit": 2
          },
          {
            "label": "Free drink",
            "redeem": 9,
            "from": "Stamp"
          }
        ]
      },
      {
        "list": "passes",
        "actions": [
          {
            "label": "Pass coffee",
            "values": {
              "item": "Coffee pass coffee"
            },
            "daily_limit": 1
          }
        ]
      }
    ],
    "plans": [
      {
        "plan": "regular",
        "name": "Regular",
        "free": true
      },
      {
        "plan": "pass",
        "name": "Coffee pass",
        "paid": true,
        "price": {
          "amount": 3000,
          "currency": "gbp",
          "interval": "month"
        }
      }
    ],
    "demo": {
      "member": {
        "name": "Hannah Okafor",
        "email": "hannah.okafor@example.com",
        "profile": {
          "name": "Hannah"
        }
      },
      "plans": [],
      "rows": {
        "orders": [
          {
            "drink": "Flat white",
            "size": "Regular",
            "milk": "Oat",
            "extra": "Extra shot",
            "pickup_date": "today",
            "pickup": "08:10",
            "cup_name": "Hannah",
            "_added": "today",
            "_status": "Ready"
          },
          {
            "drink": "Flat white",
            "size": "Regular",
            "milk": "Oat",
            "extra": "Extra shot",
            "pickup_date": "-1w:fri",
            "pickup": "08:10",
            "cup_name": "Hannah",
            "_added": "-1w:fri",
            "_status": "Collected"
          },
          {
            "drink": "Cortado",
            "size": "Small",
            "milk": "Whole",
            "pickup_date": "-1w:thu",
            "pickup": "09:30",
            "cup_name": "Hannah",
            "_added": "-1w:thu",
            "_status": "Collected"
          },
          {
            "drink": "Chai latte",
            "size": "Regular",
            "milk": "Oat",
            "extra": "Half sweet",
            "pickup_date": "-1w:tue",
            "pickup": "09:20",
            "cup_name": "Han",
            "_added": "-1w:tue",
            "_status": "Collected"
          },
          {
            "drink": "Flat white",
            "size": "Regular",
            "milk": "Oat",
            "extra": "Extra shot",
            "pickup_date": "-1w:mon",
            "pickup": "08:10",
            "cup_name": "Hannah",
            "_added": "-1w:mon",
            "_status": "Collected"
          },
          {
            "drink": "Americano",
            "size": "Small",
            "milk": "No milk",
            "extra": "Cold milk on the side",
            "pickup_date": "-2w:fri",
            "pickup": "10:10",
            "cup_name": "Hannah",
            "_added": "-2w:fri",
            "_status": "Collected"
          },
          {
            "drink": "Flat white",
            "size": "Regular",
            "milk": "Oat",
            "extra": "Extra shot",
            "pickup_date": "-2w:wed",
            "pickup": "08:20",
            "cup_name": "Hannah",
            "_added": "-2w:wed",
            "_status": "Collected"
          },
          {
            "drink": "Latte",
            "size": "Regular",
            "milk": "Oat",
            "pickup_date": "-2w:tue",
            "pickup": "08:40",
            "cup_name": "Hannah",
            "_added": "-2w:tue",
            "_status": "Collected"
          },
          {
            "drink": "Flat white",
            "size": "Regular",
            "milk": "Oat",
            "extra": "Extra shot",
            "pickup_date": "-2w:mon",
            "pickup": "08:10",
            "cup_name": "Hannah",
            "_added": "-2w:mon",
            "_status": "Collected"
          }
        ],
        "stamps": [
          {
            "item": "Order collected",
            "_added": "-1w:fri"
          },
          {
            "item": "Order collected",
            "_added": "-1w:thu"
          },
          {
            "item": "Order collected",
            "_added": "-1w:tue"
          },
          {
            "item": "Order collected",
            "_added": "-1w:mon"
          },
          {
            "item": "Order collected",
            "_added": "-2w:fri"
          },
          {
            "item": "Order collected",
            "_added": "-2w:wed"
          },
          {
            "item": "Order collected",
            "_added": "-2w:tue"
          },
          {
            "item": "Order collected",
            "_added": "-2w:mon"
          }
        ],
        "passes": []
      },
      "staff": {
        "members": [
          {
            "name": "Hannah",
            "counts": {
              "Stamp": 8
            },
            "plan": "regular",
            "since": "-24w:mon"
          },
          {
            "name": "Grace",
            "counts": {
              "Stamp": 9
            },
            "plan": "regular",
            "since": "-40w:tue"
          },
          {
            "name": "Tom",
            "counts": {
              "Stamp": 3,
              "Pass coffee": 14
            },
            "plan": "pass",
            "since": "-12w:wed"
          },
          {
            "name": "Ravi",
            "counts": {
              "Stamp": 5
            },
            "plan": "regular",
            "since": "-8w:thu"
          },
          {
            "name": "Sam",
            "counts": {
              "Stamp": 2
            },
            "plan": "regular",
            "since": "-3w:fri"
          },
          {
            "name": "Joe",
            "counts": {
              "Stamp": 2,
              "Pass coffee": 9
            },
            "plan": "pass",
            "since": "-6w:mon"
          },
          {
            "name": "Maya",
            "counts": {
              "Stamp": 4
            },
            "plan": "regular",
            "since": "-5w:tue"
          },
          {
            "name": "Elena",
            "counts": {
              "Stamp": 0
            },
            "plan": "regular",
            "since": "-0w:mon"
          }
        ],
        "log": [
          {
            "name": "Tom",
            "action": "Pass coffee",
            "at": "07:34",
            "by": "Dan"
          },
          {
            "name": "Grace",
            "action": "Stamp",
            "at": "07:41",
            "by": "Dan"
          },
          {
            "name": "Joe",
            "action": "Pass coffee",
            "at": "07:52",
            "by": "Priyanka"
          },
          {
            "name": "Sam",
            "action": "Stamp",
            "at": "08:15",
            "by": "Priyanka"
          }
        ],
        "queue": [
          {
            "name": "Maya",
            "values": {
              "drink": "Americano",
              "size": "Regular",
              "milk": "No milk",
              "pickup": "08:00",
              "cup_name": "Maya"
            },
            "status": "Ready"
          },
          {
            "name": "Ravi",
            "values": {
              "drink": "Latte",
              "size": "Small",
              "milk": "Skimmed",
              "pickup": "08:20",
              "cup_name": "Ravi"
            },
            "status": "Received"
          },
          {
            "name": "Elena",
            "values": {
              "drink": "Chai latte",
              "size": "Regular",
              "milk": "Oat",
              "extra": "Half sweet",
              "pickup": "08:30",
              "cup_name": "Elena"
            },
            "status": "Received"
          }
        ],
        "copy": {
          "show": "Show this to the barista when you collect.",
          "scanTitle": "Counter phone",
          "scanHint": "Point the camera at the code on their phone or wallet card.",
          "noun": "stamp",
          "nouns": "stamps",
          "notes": {
            "Pass coffee": "Coffee pass: one Small or Regular coffee, weekdays 07:30 to 11:00. Extras are paid.",
            "Free drink": "Any drink, size and milk. Extras are paid."
          },
          "queueNote": "Mark it Collected as it goes over the counter, then scan their code for the stamp."
        }
      }
    }
  },
  "files": [
    "index.html",
    "app/index.html",
    "app/order.html",
    "app/orders.html",
    "app/card.html",
    "app/rewards.html",
    "app/account.html",
    "privacy.html",
    "kit.css",
    "kit.js",
    "kit-icons.svg",
    "styles.css",
    "site.webmanifest",
    "favicon.svg",
    "art/pour.webp",
    "art/counter-room.webp",
    "art/filter-pour.webp",
    "art/drink-flat-white.svg",
    "art/drink-cortado.svg",
    "art/drink-latte.svg",
    "art/drink-cappuccino.svg",
    "art/drink-americano.svg",
    "art/drink-filter.svg",
    "art/drink-chai-latte.svg",
    "art/drink-hot-chocolate.svg",
    "og.png",
    "apple-touch-icon.png",
    "icon-192.png",
    "icon-512.png",
    "icon-512-maskable.png"
  ],
  "pages": [
    {
      "path": "index.html",
      "label": "Home",
      "purpose": "The public page: order ahead and collect by Hollowmere station, three steps, the menu with drawn drinks and prices, Regular or Coffee pass, and the visit details, with links into the app"
    },
    {
      "path": "app/index.html",
      "label": "App home",
      "purpose": "Signed out: the welcome screen with Continue with email. Signed in: a greeting, the stamp card (8 of 9, Show my code), today's order with its status timeline, quick actions, Order again and the counter's hours"
    },
    {
      "path": "app/order.html",
      "label": "Order",
      "purpose": "The menu as drink cards; tapping one fills the order panel (size, milk, pickup day and time, extras, name on the cup) with a running price, then Place order"
    },
    {
      "path": "app/orders.html",
      "label": "Orders",
      "purpose": "Today's order from Received to Being made, Ready and Collected (the owner's status), what happens next, and past orders with Again"
    },
    {
      "path": "app/card.html",
      "label": "Card",
      "purpose": "The member card with the code to show at the counter (and Apple Wallet and Google Wallet where on), the rules, the stamp history and Coffee pass coffees"
    },
    {
      "path": "app/rewards.html",
      "label": "Rewards",
      "purpose": "Stamps to the free drink or the free drink ready, Show my code to redeem, how it works, and the Coffee pass offer"
    },
    {
      "path": "app/account.html",
      "label": "Account",
      "purpose": "Profile, the Regular plan or the Coffee pass with Join, the wallet card, the account block (sign-in, devices, billing, leaving) and contact"
    },
    {
      "path": "privacy.html",
      "label": "Privacy",
      "purpose": "The privacy notice, with blanks the Site Owner fills in"
    }
  ],
  "facts": [
    "café name",
    "address",
    "contact email",
    "phone",
    "opening hours",
    "drink prices",
    "coffee pass price",
    "pickup window",
    "privacy contact and address"
  ],
  "interview": [
    "What is your coffee counter called, and where is it?",
    "What are your opening hours on weekdays and Saturdays?",
    "What do your drinks cost, and what does a small cost?",
    "What does the Coffee pass cost a month, and what does it cover?",
    "Which pickup times can customers choose, and how far ahead can they order?",
    "Which email address and phone number should customers use?",
    "What address and privacy contact should the privacy notice show?"
  ],
  "customise": {
    "strings": [
      "Kettle & Crane Coffee, its address, phone, email, owner and hours in the top bar, footer, titles and copy: replace every data-pl-fill fact with the owner's own. Replace the name in site.webmanifest.name too; keep short_name as Order ahead unless the owner chooses another app name.",
      "Fill in every highlighted blank on privacy.html with the Site Owner before customers use the site (not legal advice: https://pagelemon.com/agents/member-app-legal)",
      "Make the orders list with save_app_list exactly as memberApp.lists says (with its status_options: the bar moves an order from Received to Being made, Ready and Collected in the Dashboard). Change the drinks, sizes, milks and pickup times on app/order.html (the drink cards' data-k-pick and data-k-price, and the selects) and in the choice options together, and keep the list's fields the same.",
      "The stamps list and its scan actions: setup_app with memberApp.setup (open signup, the First name profile field shown to staff), then save_app_list for stamps with scan exactly as memberApp.scan says. Change the label, item value, goal and daily_limit to the owner's answers; keep the redeem number and goal the same, and the 9 on the card, rewards and home pages.",
      "Set the plans with save_plan: regular (free, pay at the counter) and pass (Coffee pass, £30 a month). Change the £30 on index.html, app/index.html, app/rewards.html and app/account.html together.",
      "Scanning adds a stamp. Staff check and update orders separately in the Dashboard; order staff need View members and Edit members permissions.",
      "Pass coffees: the Pass coffee scan action records one redemption per member per day. Staff check the weekday, time and drink rules at the counter.",
      "A coffee order only: never add health, payment card, bank or ID fields, and never collect anything about children."
    ],
    "colours": "Edit the --c-black, --c-enamel, --c-red, --c-yellow and --c-crema tokens at the top of styles.css (the --k-* kit tokens follow them); keep text pairs at 4.5:1, and light and dark follow the device. Never edit kit.css, kit.js or kit-icons.svg: they are the shared app kit (node scripts/sync-app-kit.mjs).",
    "fonts": "Google Fonts: Big Shoulders Display (the board, titles and numbers) and Figtree (text), one <link> in every page head and --c-display / --c-text in styles.css. If the owner prefers no font service, download both (OFL) into a fonts/ folder and switch to @font-face.",
    "sections": "Member pages live under /app and share one shell: the top bar with the sign-in block, the tab bar (Home, Order, Card, Rewards, Account; a black board tab strip under the red top bar from 1024 px) and data-pl-view blocks. app/index.html: the stamp card around the scan block (kit.js reads 'Stamp: 8 of 9' into the dots), today's order (orders where pickup_date >= today) and past orders. app/order.html: the add form for orders (names match the list's fields exactly). app/orders.html: the status timeline (data-k-status). app/card.html and app/rewards.html: the scan block. app/account.html: the four account parts (data-pl-part signin, profile, billing, leave) and the Coffee pass join button. index.html holds no member blocks, only links to /app.",
    "images": "art/pour.webp (signed-out welcome), art/counter-room.webp (visit) and art/filter-pour.webp (Coffee pass) are licensed stock photos (PHOTOS.md): replace them with the owner's own photos at the same shape. art/drink-*.svg are drawn top-down drinks, one per menu item (the flat white is also the station clock face on index.html); add one in the same style for a new drink, or use a square photo. favicon.svg is the mark; the PNG icons and manifest are made from it."
  },
  "schemaVersion": 2,
  "updated": "2026-10-21"
}
