feat: server-based version with menu flagging, distributed polling, and SSE

Complete implementation including:
- Express server with Bessa API proxy
- Puppeteer scraper for menu data
- Flag storage (file-based persistence)
- SSE manager for real-time updates
- Polling orchestrator for distributed polling
- Frontend with weekly view, ordering, and flagging UI
- Yellow/green glow indicators for flagged items
This commit is contained in:
2026-02-12 08:36:05 +01:00
commit bc98a19fc6
98 changed files with 17157 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
{
"cookies": [
{
"name": "__cmpcc",
"value": "1",
"domain": "web.bessa.app",
"path": "/",
"expires": 1804426749,
"size": 8,
"httpOnly": false,
"secure": true,
"session": false,
"sameSite": "Lax",
"priority": "Medium",
"sameParty": false,
"sourceScheme": "Secure",
"sourcePort": 443
},
{
"name": "g_state",
"value": "{\"i_l\":0,\"i_ll\":1770298749698,\"i_b\":\"OwmjB/xOTtJtApPjLsCx6Vw3vtuduXvkmTEMjNJSXuE\",\"i_e\":{\"enable_itp_optimization\":15}}",
"domain": "web.bessa.app",
"path": "/",
"expires": 1785850749,
"size": 126,
"httpOnly": false,
"secure": false,
"session": false,
"priority": "Medium",
"sameParty": false,
"sourceScheme": "Secure",
"sourcePort": 443
},
{
"name": "_fbp",
"value": "fb.1.1770298749735.57921644138573676",
"domain": ".bessa.app",
"path": "/",
"expires": 1778074808,
"size": 40,
"httpOnly": false,
"secure": false,
"session": false,
"sameSite": "Lax",
"priority": "Medium",
"sameParty": false,
"sourceScheme": "Secure",
"sourcePort": 443
},
{
"name": "_ga",
"value": "GA1.1.531786136.1770298750",
"domain": ".bessa.app",
"path": "/",
"expires": 1804858750.164727,
"size": 29,
"httpOnly": false,
"secure": false,
"session": false,
"priority": "Medium",
"sameParty": false,
"sourceScheme": "Secure",
"sourcePort": 443
},
{
"name": "__cmpconsent16021",
"value": "CQfJhpgQfJhpgAfS8BENCQFgAAAAAAAAAAigF5wAQF5gXnABAXmAAA",
"domain": ".bessa.app",
"path": "/",
"expires": 1801834763,
"size": 71,
"httpOnly": false,
"secure": true,
"session": false,
"sameSite": "None",
"priority": "Medium",
"sameParty": false,
"sourceScheme": "Secure",
"sourcePort": 443
},
{
"name": "__cmpcccu16021",
"value": "aCQfLid1gA6XgGsY5PMqNQExowBZVC0A0QwAgQIRoBSm",
"domain": ".bessa.app",
"path": "/",
"expires": 1801834763,
"size": 58,
"httpOnly": false,
"secure": true,
"session": false,
"sameSite": "None",
"priority": "Medium",
"sameParty": false,
"sourceScheme": "Secure",
"sourcePort": 443
},
{
"name": "_ga_NT5W7DSRT4",
"value": "GS2.1.s1770298750$o1$g1$t1770298809$j1$l0$h0",
"domain": ".bessa.app",
"path": "/",
"expires": 1804858809.787043,
"size": 58,
"httpOnly": false,
"secure": false,
"session": false,
"priority": "Medium",
"sameParty": false,
"sourceScheme": "Secure",
"sourcePort": 443
}
]
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"lastExternalReferrerTime":"1770298749727","__cmpconsent16021_.bessa.app":"CQfJhpgQfJhpgAfS8BENCQFgAAAAAAAAAAigF5wAQF5gXnABAXmAAA","topicsLastReferenceTime":"1770298808783","__cmpconsent16021_expire_.bessa.app":"1801834763719","lastExternalReferrer":"empty","__cmpcccu16021_.bessa.app":"aCQfLid1gA6XgGsY5PMqNQExowBZVC0A0QwAgQIRoBSm","__cmpcccu16021_expire_.bessa.app":"1801834763719","AkitaStores":"{\"$cache\":{\"auth\":false},\"auth\":{\"askedForNotifications\":false,\"token\":\"dba7d86e83c7f462fd8af96521dea41c4facd8a5\",\"user\":{\"id\":85567,\"lastLogin\":\"2026-02-05T13:40:04.251Z\",\"created\":\"2025-11-26T22:22:46.535Z\",\"updated\":\"2025-12-09T07:26:02.309Z\",\"email\":\"knapp-2041@bessa.app\",\"firstName\":\"Michael\",\"lastName\":\"Kaufmann\",\"locale\":\"de_de\",\"country\":\"\",\"language\":\"de\",\"profile\":null,\"uuid\":\"de0e6518-f917-4679-afd1-47a6f5e22a55\",\"groups\":[\"Managed\"],\"dateOfBirth\":null,\"passwordChanged\":\"2025-12-09T07:26:02.304Z\",\"gender\":1}}}"}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,131 @@
{
"capturedAt": "2026-02-11T10:15:00Z",
"description": "Captured API traffic from Bessa web app during order placement and cancellation",
"apiCalls": [
{
"step": "1. Fetch available dates (with existing orders)",
"method": "GET",
"url": "https://api.bessa.app/v1/venues/591/menu/dates/",
"requestHeaders": {
"Accept": "application/json",
"Authorization": "Token dba7d86e83c7f462fd8af96521dea41c4facd8a5",
"X-Client-Version": "1.7.0_prod/2026-01-26"
},
"responseStatus": 200,
"responseBody": {
"results": [
{
"date": "2026-02-11",
"id": 691,
"orders": [
{
"id": 1522671,
"order_state": 8,
"total": "5.50",
"items": [
{
"name": "M1 Herzhaftes"
}
]
}
]
},
{
"date": "2026-02-12",
"id": 692,
"orders": [
{
"id": 1522672,
"order_state": 5,
"total": "5.50",
"items": [
{
"name": "M5F Salat mit Gebäck DO 2"
}
]
}
]
},
{
"date": "2026-02-13",
"id": 698,
"orders": []
}
]
},
"duration": 202
},
{
"step": "2. Place order (POST)",
"method": "POST",
"url": "https://api.bessa.app/v1/user/orders/",
"requestHeaders": {
"Accept": "application/json",
"Authorization": "Token dba7d86e83c7f462fd8af96521dea41c4facd8a5",
"Content-Type": "application/json"
},
"requestBody": {
"customer": {
"email": "knapp-2041@bessa.app",
"first_name": "Michael",
"last_name": "Kaufmann"
},
"date": "2026-02-13T10:00:00.000Z",
"items": [
{
"amount": 1,
"article": 182378,
"name": "M1 W2",
"price": 4,
"vat": "10.00"
}
],
"order_type": 7,
"payment_method": "payroll",
"total": 4,
"venue": 591
},
"responseStatus": 201,
"responseBody": {
"id": 1535066,
"hash_id": "o_xlOaq",
"order_state": 5,
"total": "4.00"
},
"duration": 269
},
{
"step": "3. Cancel order (PATCH)",
"method": "PATCH",
"url": "https://api.bessa.app/v1/user/orders/1535066/cancel/",
"requestHeaders": {
"Accept": "application/json",
"Authorization": "Token dba7d86e83c7f462fd8af96521dea41c4facd8a5",
"Content-Type": "application/json"
},
"requestBody": {},
"responseStatus": 200,
"responseBody": {
"order_id": "o_xlOaq",
"state": "order cancelled."
},
"duration": 133
}
],
"orderStates": {
"5": "Transmitted/Active (new order)",
"8": "Accepted/Processed (confirmed by kitchen)"
},
"configurationDetails": {
"orderType": 7,
"configName": "canteen",
"paymentTypes": [
"payroll"
],
"cancellationCutoff": 3600,
"allowCancel": true,
"preorderDelta": 3600,
"venueId": 591,
"venueTimezone": "CET"
}
}

File diff suppressed because one or more lines are too long