-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmind-map.html
44 lines (44 loc) · 54.8 KB
/
mind-map.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Markmap</title>
<style>
* {
margin: 0;
padding: 0;
}
#mindmap {
display: block;
width: 100vw;
height: 100vh;
}
</style>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@highlightjs/cdn-assets@11.8.0/styles/default.min.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/markmap-toolbar@0.17.2/dist/style.css">
</head>
<body>
<svg id="mindmap"></svg>
<script src="https://cdn.jsdelivr.net/npm/d3@7.8.5/dist/d3.min.js"></script><script src="https://cdn.jsdelivr.net/npm/markmap-view@0.17.2/dist/browser/index.js"></script><script src="https://cdn.jsdelivr.net/npm/markmap-toolbar@0.17.2/dist/index.js"></script><script>(r => {
setTimeout(r);
})(() => {
const {
markmap,
mm
} = window;
const {
el
} = markmap.Toolbar.create(mm);
el.setAttribute('style', 'position:absolute;bottom:20px;right:20px');
document.body.append(el);
})</script><script>((getMarkmap, getOptions, root2, jsonOptions) => {
const markmap = getMarkmap();
window.mm = markmap.Markmap.create(
"svg#mindmap",
(getOptions || markmap.deriveOptions)(jsonOptions),
root2
);
})(() => window.markmap,null,{"content":"Architecture Document for Supermarket Receipt Parsers and Nutri-Scanorama v2","children":[{"content":"Overview","children":[],"payload":{"lines":"2,3"}},{"content":"List of Major German Supermarkets","children":[{"content":"<strong>REWE</strong>","children":[],"payload":{"lines":"6,7"}},{"content":"<strong>Aldi (Aldi Nord and Aldi Süd)</strong>","children":[],"payload":{"lines":"7,8"}},{"content":"<strong>Lidl</strong>","children":[],"payload":{"lines":"8,9"}},{"content":"<strong>Edeka</strong>","children":[],"payload":{"lines":"9,10"}},{"content":"<strong>Penny</strong>","children":[],"payload":{"lines":"10,11"}},{"content":"<strong>Netto</strong>","children":[],"payload":{"lines":"11,12"}},{"content":"<strong>Kaufland</strong>","children":[],"payload":{"lines":"12,13"}},{"content":"<strong>Real</strong>","children":[],"payload":{"lines":"13,14"}},{"content":"<strong>dm (Drogerie Markt)</strong>","children":[],"payload":{"lines":"14,15"}},{"content":"<strong>Rossmann</strong>","children":[],"payload":{"lines":"15,17"}}],"payload":{"lines":"5,6"}},{"content":"Strategy for Implementing Supermarket Parsers","children":[{"content":"\n<p data-lines=\"19,20\"><strong>Define Parser Requirements</strong></p>","children":[{"content":"Each parser should extract relevant data: store name, address, purchase date, item details (name, quantity, price), total amount, and tax details.","children":[],"payload":{"lines":"20,21"}},{"content":"Analyze sample receipts to identify patterns and common elements for each supermarket.","children":[],"payload":{"lines":"21,23"}}],"payload":{"lines":"19,23"}},{"content":"\n<p data-lines=\"23,24\"><strong>Create a Generic Parser Interface</strong></p>","children":[{"content":"Define a common interface or base class for all parsers to ensure consistency and easier management.","children":[],"payload":{"lines":"24,25"}},{"content":"Example interface:<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">interface</span> <span class=\"hljs-title class_\">SupermarketParser</span> {\n <span class=\"hljs-title function_\">parseReceipt</span>(<span class=\"hljs-attr\">text</span>: <span class=\"hljs-built_in\">string</span>, <span class=\"hljs-attr\">receiptId</span>: <span class=\"hljs-built_in\">number</span>): <span class=\"hljs-title class_\">Promise</span><<span class=\"hljs-title class_\">ParsedReceipt</span>>;\n}\n</code></pre>","children":[],"payload":{"lines":"25,32"}}],"payload":{"lines":"23,32"}},{"content":"\n<p data-lines=\"32,33\"><strong>Implement Individual Parsers</strong></p>","children":[{"content":"Implement a dedicated parser for each supermarket that adheres to the defined interface, handling the specific receipt format.","children":[],"payload":{"lines":"33,34"}},{"content":"Example functions: <code>parseAldiReceipt</code>, <code>parseLidlReceipt</code>, etc.","children":[],"payload":{"lines":"34,36"}}],"payload":{"lines":"32,36"}},{"content":"\n<p data-lines=\"36,37\"><strong>Modify the Existing Codebase</strong></p>","children":[{"content":"Update the upload and parsing logic to accommodate the new parsers. Modify the <code>handleFileUpload</code> function to check for keywords or patterns that identify the supermarket and call the appropriate parser.","children":[],"payload":{"lines":"37,38"}},{"content":"Example modification:<pre><code class=\"language-javascript\"><span class=\"hljs-keyword\">const</span> isAldi = result.<span class=\"hljs-property\">data</span>.<span class=\"hljs-property\">text</span>.<span class=\"hljs-title function_\">includes</span>(<span class=\"hljs-string\">'Aldi'</span>);\n<span class=\"hljs-keyword\">const</span> isLidl = result.<span class=\"hljs-property\">data</span>.<span class=\"hljs-property\">text</span>.<span class=\"hljs-title function_\">includes</span>(<span class=\"hljs-string\">'Lidl'</span>);\n<span class=\"hljs-keyword\">const</span> parsedData = <span class=\"hljs-keyword\">await</span> (isAldi \n ? <span class=\"hljs-title function_\">parseAldiReceipt</span>(result.<span class=\"hljs-property\">data</span>.<span class=\"hljs-property\">text</span>, receiptId)\n : isLidl \n ? <span class=\"hljs-title function_\">parseLidlReceipt</span>(result.<span class=\"hljs-property\">data</span>.<span class=\"hljs-property\">text</span>, receiptId)\n : <span class=\"hljs-title function_\">parseReweReceipt</span>(result.<span class=\"hljs-property\">data</span>.<span class=\"hljs-property\">text</span>, receiptId));\n</code></pre>","children":[],"payload":{"lines":"38,49"}}],"payload":{"lines":"36,49"}}],"payload":{"lines":"17,18"}},{"content":"Receipt Processing Architecture","children":[{"content":"Store Name Handling","children":[{"content":"The logic for determining the store name based on parsed receipt data will be handled in the <code>UploadButton</code> component after the parsing step.","children":[],"payload":{"lines":"52,53"}},{"content":"If the store name is identified as 'Other', the user will be prompted to enter the correct store name.","children":[],"payload":{"lines":"53,54"}},{"content":"This change ensures that the parsers remain focused solely on parsing tasks without incorporating business logic related to store identification.","children":[],"payload":{"lines":"54,56"}}],"payload":{"lines":"51,52"}},{"content":"Default Receipt Parser Implementation","children":[{"content":"<strong>Purpose</strong>: Created a default receipt parser to handle unknown receipts. This parser prompts the user for missing information, such as the store name and address, if items are found in the receipt.","children":[],"payload":{"lines":"57,58"}},{"content":"<strong>Error Handling</strong>: If no items are found, the parser throws a <code>ReceiptValidationError</code> indicating that no valid items were detected.","children":[],"payload":{"lines":"58,59"}},{"content":"<strong>Integration</strong>: The default parser is invoked when no recognized store is identified during the parsing process, ensuring that user input is captured for completeness.","children":[],"payload":{"lines":"59,61"}}],"payload":{"lines":"56,57"}}],"payload":{"lines":"49,50"}},{"content":"AI Integration","children":[{"content":"Overview","children":[{"content":"Automatic item extraction from receipt text","children":[],"payload":{"lines":"65,66"}},{"content":"Smart retry system with up to 3 attempts","children":[],"payload":{"lines":"66,67"}},{"content":"Real-time progress tracking and user feedback","children":[],"payload":{"lines":"67,68"}},{"content":"Automatic category assignment","children":[],"payload":{"lines":"68,69"}},{"content":"Integration with sync queue and local database","children":[],"payload":{"lines":"69,71"}}],"payload":{"lines":"63,64"}},{"content":"Ollama Service Implementation","children":[{"content":"Processes raw receipt text to extract structured item data","children":[],"payload":{"lines":"72,73"}},{"content":"Handles validation and error cases","children":[],"payload":{"lines":"73,74"}},{"content":"Provides detailed feedback for debugging","children":[],"payload":{"lines":"74,75"}},{"content":"Supports both initial processing and manual retries","children":[],"payload":{"lines":"75,77"}}],"payload":{"lines":"71,72"}},{"content":"User Interface Integration","children":[{"content":"Progress indicators during extraction","children":[],"payload":{"lines":"78,79"}},{"content":"Clear success/error notifications","children":[],"payload":{"lines":"79,80"}},{"content":"Manual retry option with attempt tracking","children":[],"payload":{"lines":"80,81"}},{"content":"Real-time updates of extracted items","children":[],"payload":{"lines":"81,83"}}],"payload":{"lines":"77,78"}},{"content":"Data Flow","children":[{"content":"Receipt text → Ollama processing → Structured items","children":[],"payload":{"lines":"84,85"}},{"content":"Automatic category assignment","children":[],"payload":{"lines":"85,86"}},{"content":"Database updates and sync queue integration","children":[],"payload":{"lines":"86,87"}},{"content":"UI state management and updates","children":[],"payload":{"lines":"87,89"}}],"payload":{"lines":"83,84"}}],"payload":{"lines":"61,62"}},{"content":"AI Text Extraction and Processing","children":[{"content":"Overview","children":[],"payload":{"lines":"91,92"}},{"content":"Core Components","children":[{"content":"\n<p data-lines=\"96,97\"><strong>OCR Processing</strong></p>\n<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">interface</span> <span class=\"hljs-title class_\">OCRResult</span> {\n <span class=\"hljs-attr\">text</span>: <span class=\"hljs-built_in\">string</span>;\n <span class=\"hljs-attr\">confidence</span>: <span class=\"hljs-built_in\">number</span>;\n <span class=\"hljs-attr\">blocks</span>: <span class=\"hljs-title class_\">Array</span><{\n <span class=\"hljs-attr\">text</span>: <span class=\"hljs-built_in\">string</span>;\n <span class=\"hljs-attr\">bbox</span>: <span class=\"hljs-title class_\">BoundingBox</span>;\n <span class=\"hljs-attr\">confidence</span>: <span class=\"hljs-built_in\">number</span>;\n }>;\n}\n</code></pre>","children":[{"content":"Tesseract.js for text extraction","children":[],"payload":{"lines":"108,109"}},{"content":"Block-level confidence scoring","children":[],"payload":{"lines":"109,110"}},{"content":"Position information preservation","children":[],"payload":{"lines":"110,111"}},{"content":"Multi-language support","children":[],"payload":{"lines":"111,113"}}],"payload":{"lines":"96,113"}},{"content":"\n<p data-lines=\"113,114\"><strong>LLM Processing</strong></p>\n<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">interface</span> <span class=\"hljs-title class_\">ProcessedReceipt</span> {\n <span class=\"hljs-attr\">storeName</span>: <span class=\"hljs-built_in\">string</span>;\n <span class=\"hljs-attr\">items</span>: <span class=\"hljs-title class_\">Array</span><{\n <span class=\"hljs-attr\">name</span>: <span class=\"hljs-built_in\">string</span>;\n <span class=\"hljs-attr\">category</span>: <span class=\"hljs-title class_\">CategoryName</span>;\n <span class=\"hljs-attr\">price</span>: <span class=\"hljs-built_in\">number</span>;\n quantity?: <span class=\"hljs-built_in\">number</span>;\n unit?: <span class=\"hljs-built_in\">string</span>;\n pricePerUnit?: <span class=\"hljs-built_in\">number</span>;\n taxRate?: <span class=\"hljs-built_in\">string</span>;\n }>;\n <span class=\"hljs-attr\">metadata</span>: {\n storeAddress?: <span class=\"hljs-built_in\">string</span>;\n date?: <span class=\"hljs-built_in\">string</span>;\n <span class=\"hljs-attr\">totalAmount</span>: <span class=\"hljs-built_in\">number</span>;\n taxDetails?: {\n <span class=\"hljs-attr\">taxRateA</span>: { <span class=\"hljs-attr\">rate</span>: <span class=\"hljs-built_in\">number</span>, <span class=\"hljs-attr\">net</span>: <span class=\"hljs-built_in\">number</span>, <span class=\"hljs-attr\">tax</span>: <span class=\"hljs-built_in\">number</span>, <span class=\"hljs-attr\">gross</span>: <span class=\"hljs-built_in\">number</span> };\n taxRateB?: { <span class=\"hljs-attr\">rate</span>: <span class=\"hljs-built_in\">number</span>, <span class=\"hljs-attr\">net</span>: <span class=\"hljs-built_in\">number</span>, <span class=\"hljs-attr\">tax</span>: <span class=\"hljs-built_in\">number</span>, <span class=\"hljs-attr\">gross</span>: <span class=\"hljs-built_in\">number</span> };\n };\n };\n}\n</code></pre>","children":[{"content":"Structured data extraction","children":[],"payload":{"lines":"137,138"}},{"content":"Category assignment","children":[],"payload":{"lines":"138,139"}},{"content":"Price and quantity parsing","children":[],"payload":{"lines":"139,140"}},{"content":"Tax information extraction","children":[],"payload":{"lines":"140,142"}}],"payload":{"lines":"113,142"}},{"content":"\n<p data-lines=\"142,143\"><strong>Model Selection</strong></p>\n<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">type</span> <span class=\"hljs-title class_\">ModelType</span> = <span class=\"hljs-string\">'fast'</span> | <span class=\"hljs-string\">'precise'</span>;\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">MODELS</span> = {\n <span class=\"hljs-attr\">fast</span>: <span class=\"hljs-string\">'meta-llama-3.2-1b'</span>,\n <span class=\"hljs-attr\">precise</span>: <span class=\"hljs-string\">'qwen2.5-coder-32b-instruct'</span>\n};\n</code></pre>","children":[{"content":"Dual model approach","children":[],"payload":{"lines":"151,152"}},{"content":"Performance vs accuracy tradeoff","children":[],"payload":{"lines":"152,153"}},{"content":"Automatic fallback mechanisms","children":[],"payload":{"lines":"153,155"}}],"payload":{"lines":"142,155"}}],"payload":{"lines":"94,95"}},{"content":"Processing Pipeline","children":[{"content":"\n<p data-lines=\"157,158\"><strong>Image Preprocessing</strong></p>","children":[{"content":"Resolution optimization","children":[],"payload":{"lines":"158,159"}},{"content":"Contrast enhancement","children":[],"payload":{"lines":"159,160"}},{"content":"Noise reduction","children":[],"payload":{"lines":"160,161"}},{"content":"Orientation correction","children":[],"payload":{"lines":"161,163"}}],"payload":{"lines":"157,163"}},{"content":"\n<p data-lines=\"163,164\"><strong>Text Extraction</strong></p>","children":[{"content":"OCR processing","children":[],"payload":{"lines":"164,165"}},{"content":"Confidence filtering","children":[],"payload":{"lines":"165,166"}},{"content":"Layout analysis","children":[],"payload":{"lines":"166,167"}},{"content":"Text cleaning","children":[],"payload":{"lines":"167,169"}}],"payload":{"lines":"163,169"}},{"content":"\n<p data-lines=\"169,170\"><strong>Data Structuring</strong></p>","children":[{"content":"Store detection","children":[],"payload":{"lines":"170,171"}},{"content":"Item parsing","children":[],"payload":{"lines":"171,172"}},{"content":"Price extraction","children":[],"payload":{"lines":"172,173"}},{"content":"Category assignment","children":[],"payload":{"lines":"173,175"}}],"payload":{"lines":"169,175"}}],"payload":{"lines":"155,156"}},{"content":"Design Decisions","children":[{"content":"\n<p data-lines=\"177,178\"><strong>Dual Model Strategy</strong></p>","children":[{"content":"<strong>Decision</strong>: Implement both fast and precise models","children":[],"payload":{"lines":"178,179"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Balances speed and accuracy","children":[],"payload":{"lines":"180,181"}},{"content":"Handles varying receipt complexity","children":[],"payload":{"lines":"181,182"}},{"content":"Optimizes resource usage","children":[],"payload":{"lines":"182,183"}},{"content":"Provides user choice","children":[],"payload":{"lines":"183,185"}}],"payload":{"lines":"179,185"}}],"payload":{"lines":"177,185"}},{"content":"\n<p data-lines=\"185,186\"><strong>Strict Category Enforcement</strong></p>","children":[{"content":"<strong>Decision</strong>: Use predefined category set","children":[],"payload":{"lines":"186,187"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Ensures data consistency","children":[],"payload":{"lines":"188,189"}},{"content":"Improves categorization accuracy","children":[],"payload":{"lines":"189,190"}},{"content":"Simplifies reporting","children":[],"payload":{"lines":"190,191"}},{"content":"Better user experience","children":[],"payload":{"lines":"191,193"}}],"payload":{"lines":"187,193"}}],"payload":{"lines":"185,193"}},{"content":"\n<p data-lines=\"193,194\"><strong>Structured Response Format</strong></p>","children":[{"content":"<strong>Decision</strong>: Enforce strict JSON schema","children":[],"payload":{"lines":"194,195"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Reliable parsing","children":[],"payload":{"lines":"196,197"}},{"content":"Type safety","children":[],"payload":{"lines":"197,198"}},{"content":"Error prevention","children":[],"payload":{"lines":"198,199"}},{"content":"Easy validation","children":[],"payload":{"lines":"199,201"}}],"payload":{"lines":"195,201"}}],"payload":{"lines":"193,201"}},{"content":"\n<p data-lines=\"201,202\"><strong>Progressive Processing</strong></p>","children":[{"content":"<strong>Decision</strong>: Multi-stage extraction pipeline","children":[],"payload":{"lines":"202,203"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Better error handling","children":[],"payload":{"lines":"204,205"}},{"content":"Incremental feedback","children":[],"payload":{"lines":"205,206"}},{"content":"Recovery options","children":[],"payload":{"lines":"206,207"}},{"content":"Performance optimization","children":[],"payload":{"lines":"207,209"}}],"payload":{"lines":"203,209"}}],"payload":{"lines":"201,209"}}],"payload":{"lines":"175,176"}},{"content":"Error Handling","children":[{"content":"\n<p data-lines=\"211,212\"><strong>OCR Failures</strong></p>","children":[{"content":"Confidence thresholds","children":[],"payload":{"lines":"212,213"}},{"content":"Retry mechanisms","children":[],"payload":{"lines":"213,214"}},{"content":"Alternative processing paths","children":[],"payload":{"lines":"214,215"}},{"content":"User feedback","children":[],"payload":{"lines":"215,217"}}],"payload":{"lines":"211,217"}},{"content":"\n<p data-lines=\"217,218\"><strong>LLM Processing</strong></p>","children":[{"content":"Response validation","children":[],"payload":{"lines":"218,219"}},{"content":"Fallback processing","children":[],"payload":{"lines":"219,220"}},{"content":"Format correction","children":[],"payload":{"lines":"220,221"}},{"content":"Error reporting","children":[],"payload":{"lines":"221,223"}}],"payload":{"lines":"217,223"}}],"payload":{"lines":"209,210"}},{"content":"Performance Optimization","children":[{"content":"\n<p data-lines=\"225,226\"><strong>Processing Strategy</strong></p>","children":[{"content":"Parallel processing where possible","children":[],"payload":{"lines":"226,227"}},{"content":"Caching of intermediate results","children":[],"payload":{"lines":"227,228"}},{"content":"Resource usage monitoring","children":[],"payload":{"lines":"228,229"}},{"content":"Background processing","children":[],"payload":{"lines":"229,231"}}],"payload":{"lines":"225,231"}},{"content":"\n<p data-lines=\"231,232\"><strong>Memory Management</strong></p>","children":[{"content":"Efficient data structures","children":[],"payload":{"lines":"232,233"}},{"content":"Stream processing","children":[],"payload":{"lines":"233,234"}},{"content":"Resource cleanup","children":[],"payload":{"lines":"234,235"}},{"content":"Memory limits","children":[],"payload":{"lines":"235,237"}}],"payload":{"lines":"231,237"}}],"payload":{"lines":"223,224"}},{"content":"Future Enhancements","children":[{"content":"\n<p data-lines=\"239,240\"><strong>Model Improvements</strong></p>","children":[{"content":"Custom model training","children":[],"payload":{"lines":"240,241"}},{"content":"Receipt-specific fine-tuning","children":[],"payload":{"lines":"241,242"}},{"content":"Multi-language support","children":[],"payload":{"lines":"242,243"}},{"content":"Performance optimization","children":[],"payload":{"lines":"243,245"}}],"payload":{"lines":"239,245"}},{"content":"\n<p data-lines=\"245,246\"><strong>Feature Additions</strong></p>","children":[{"content":"Advanced tax handling","children":[],"payload":{"lines":"246,247"}},{"content":"Currency conversion","children":[],"payload":{"lines":"247,248"}},{"content":"Receipt comparison","children":[],"payload":{"lines":"248,249"}},{"content":"Fraud detection","children":[],"payload":{"lines":"249,251"}}],"payload":{"lines":"245,251"}}],"payload":{"lines":"237,238"}},{"content":"Testing Strategy","children":[{"content":"\n<p data-lines=\"253,254\"><strong>Unit Tests</strong></p>","children":[{"content":"OCR accuracy","children":[],"payload":{"lines":"254,255"}},{"content":"Parser reliability","children":[],"payload":{"lines":"255,256"}},{"content":"Category assignment","children":[],"payload":{"lines":"256,257"}},{"content":"Error handling","children":[],"payload":{"lines":"257,259"}}],"payload":{"lines":"253,259"}},{"content":"\n<p data-lines=\"259,260\"><strong>Integration Tests</strong></p>","children":[{"content":"End-to-end processing","children":[],"payload":{"lines":"260,261"}},{"content":"Model switching","children":[],"payload":{"lines":"261,262"}},{"content":"Error recovery","children":[],"payload":{"lines":"262,263"}},{"content":"Performance metrics","children":[],"payload":{"lines":"263,265"}}],"payload":{"lines":"259,265"}}],"payload":{"lines":"251,252"}},{"content":"Security Considerations","children":[{"content":"\n<p data-lines=\"267,268\"><strong>Data Protection</strong></p>","children":[{"content":"Personal information handling","children":[],"payload":{"lines":"268,269"}},{"content":"Data retention policies","children":[],"payload":{"lines":"269,270"}},{"content":"Access controls","children":[],"payload":{"lines":"270,271"}},{"content":"Encryption","children":[],"payload":{"lines":"271,273"}}],"payload":{"lines":"267,273"}},{"content":"\n<p data-lines=\"273,274\"><strong>Model Security</strong></p>","children":[{"content":"Input validation","children":[],"payload":{"lines":"274,275"}},{"content":"Output sanitization","children":[],"payload":{"lines":"275,276"}},{"content":"Resource limits","children":[],"payload":{"lines":"276,277"}},{"content":"Version control","children":[],"payload":{"lines":"277,279"}}],"payload":{"lines":"273,279"}}],"payload":{"lines":"265,266"}}],"payload":{"lines":"89,90"}},{"content":"Category Management System","children":[{"content":"Overview","children":[],"payload":{"lines":"281,282"}},{"content":"Core Components","children":[{"content":"\n<p data-lines=\"286,287\"><strong>Category Data Structure</strong></p>\n<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">type</span> <span class=\"hljs-title class_\">CategoryName</span> = \n | <span class=\"hljs-string\">'Fruits'</span> | <span class=\"hljs-string\">'Vegetables'</span> | <span class=\"hljs-string\">'Dairy'</span> | <span class=\"hljs-string\">'Meat'</span>\n | <span class=\"hljs-string\">'Bakery'</span> | <span class=\"hljs-string\">'Beverages'</span> | <span class=\"hljs-string\">'Snacks'</span> | <span class=\"hljs-string\">'Cereals'</span>\n | <span class=\"hljs-string\">'Other'</span> | <span class=\"hljs-string\">'Sweets'</span> | <span class=\"hljs-string\">'Oils'</span>;\n</code></pre>","children":[{"content":"Fixed set of categories to ensure consistency","children":[],"payload":{"lines":"293,294"}},{"content":"Each category has an associated color for visual identification","children":[],"payload":{"lines":"294,295"}},{"content":"'Other' category serves as a fallback for uncategorized items","children":[],"payload":{"lines":"295,297"}}],"payload":{"lines":"286,297"}},{"content":"\n<p data-lines=\"297,298\"><strong>Category Mapping System</strong></p>","children":[{"content":"Maintains a database of keyword-to-category mappings","children":[],"payload":{"lines":"298,299"}},{"content":"Supports both manual and AI-generated mappings","children":[],"payload":{"lines":"299,300"}},{"content":"Uses case-insensitive matching for better accuracy","children":[],"payload":{"lines":"300,301"}},{"content":"Mappings are stored in IndexedDB for offline access","children":[],"payload":{"lines":"301,303"}}],"payload":{"lines":"297,303"}},{"content":"\n<p data-lines=\"303,304\"><strong>AI Integration</strong></p>","children":[{"content":"Uses Ollama service for intelligent categorization","children":[],"payload":{"lines":"304,305"}},{"content":"Strict prompt engineering to ensure category consistency","children":[],"payload":{"lines":"305,306"}},{"content":"Fallback mechanisms for handling unknown items","children":[],"payload":{"lines":"306,307"}},{"content":"Real-time processing with user feedback","children":[],"payload":{"lines":"307,309"}}],"payload":{"lines":"303,309"}}],"payload":{"lines":"284,285"}},{"content":"User Interface Design","children":[{"content":"\n<p data-lines=\"311,312\"><strong>Category Manager Component</strong></p>","children":[{"content":"Collapsible category sections for better organization","children":[],"payload":{"lines":"312,313"}},{"content":"Preview mode showing limited items per category","children":[],"payload":{"lines":"313,314"}},{"content":"\"Show More\" functionality for detailed viewing","children":[],"payload":{"lines":"314,315"}},{"content":"Immediate feedback for all user actions","children":[],"payload":{"lines":"315,316"}},{"content":"Integrated AI categorization for bulk processing","children":[],"payload":{"lines":"316,318"}}],"payload":{"lines":"311,318"}},{"content":"\n<p data-lines=\"318,319\"><strong>Settings Integration</strong></p>","children":[{"content":"Category management placed in Settings for easy access","children":[],"payload":{"lines":"319,320"}},{"content":"Clear separation from storage management","children":[],"payload":{"lines":"320,321"}},{"content":"Intuitive interface for adding/removing mappings","children":[],"payload":{"lines":"321,322"}},{"content":"Visual feedback through toast notifications","children":[],"payload":{"lines":"322,324"}}],"payload":{"lines":"318,324"}}],"payload":{"lines":"309,310"}},{"content":"Data Flow","children":[{"content":"\n<p data-lines=\"326,327\"><strong>Manual Categorization</strong></p>\n<pre><code data-lines=\"327,330\"><span class=\"hljs-keyword\">User</span> <span class=\"hljs-keyword\">Input</span> → Keyword/Category Selection → <span class=\"hljs-keyword\">Database</span> <span class=\"hljs-keyword\">Update</span> → UI <span class=\"hljs-keyword\">Refresh</span>\n</code></pre>","children":[],"payload":{"lines":"326,331"}},{"content":"\n<p data-lines=\"331,332\"><strong>AI Categorization</strong></p>\n<pre><code data-lines=\"332,335\"><span class=\"hljs-type\">Text</span> <span class=\"hljs-keyword\">Input</span> → Ollama Processing → <span class=\"hljs-keyword\">Mapping</span> Creation → <span class=\"hljs-keyword\">Database</span> <span class=\"hljs-keyword\">Update</span> → UI <span class=\"hljs-keyword\">Refresh</span>\n</code></pre>","children":[],"payload":{"lines":"331,336"}},{"content":"\n<p data-lines=\"336,337\"><strong>Category Mapping Usage</strong></p>\n<pre><code data-lines=\"337,340\"><span class=\"hljs-variable\">Receipt</span> <span class=\"hljs-variable\">Upload</span> → <span class=\"hljs-built_in\">Item</span> <span class=\"hljs-variable\">Extraction</span> → <span class=\"hljs-variable\">Category</span> <span class=\"hljs-built_in\">Lookup</span> → <span class=\"hljs-built_in\">Default</span><span class=\"hljs-operator\">/</span><span class=\"hljs-variable\">AI</span> <span class=\"hljs-variable\">Assignment</span>\n</code></pre>","children":[],"payload":{"lines":"336,341"}}],"payload":{"lines":"324,325"}},{"content":"Design Decisions","children":[{"content":"\n<p data-lines=\"343,344\"><strong>Fixed Category Set</strong></p>","children":[{"content":"<strong>Decision</strong>: Use a fixed set of categories rather than user-defined categories","children":[],"payload":{"lines":"344,345"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Ensures consistency across the application","children":[],"payload":{"lines":"346,347"}},{"content":"Simplifies AI training and categorization","children":[],"payload":{"lines":"347,348"}},{"content":"Prevents category proliferation","children":[],"payload":{"lines":"348,349"}},{"content":"Makes statistics and visualization more meaningful","children":[],"payload":{"lines":"349,351"}}],"payload":{"lines":"345,351"}}],"payload":{"lines":"343,351"}},{"content":"\n<p data-lines=\"351,352\"><strong>Two-Tier Categorization</strong></p>","children":[{"content":"<strong>Decision</strong>: Implement both manual and AI-powered categorization","children":[],"payload":{"lines":"352,353"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Manual mappings provide precise control","children":[],"payload":{"lines":"354,355"}},{"content":"AI categorization handles bulk processing","children":[],"payload":{"lines":"355,356"}},{"content":"Hybrid approach maximizes accuracy and efficiency","children":[],"payload":{"lines":"356,358"}}],"payload":{"lines":"353,358"}}],"payload":{"lines":"351,358"}},{"content":"\n<p data-lines=\"358,359\"><strong>Collapsible UI</strong></p>","children":[{"content":"<strong>Decision</strong>: Use collapsible sections with preview mode","children":[],"payload":{"lines":"359,360"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Reduces visual clutter","children":[],"payload":{"lines":"361,362"}},{"content":"Improves navigation in large datasets","children":[],"payload":{"lines":"362,363"}},{"content":"Maintains access to full information when needed","children":[],"payload":{"lines":"363,365"}}],"payload":{"lines":"360,365"}}],"payload":{"lines":"358,365"}},{"content":"\n<p data-lines=\"365,366\"><strong>Local Storage</strong></p>","children":[{"content":"<strong>Decision</strong>: Store category mappings in IndexedDB","children":[],"payload":{"lines":"366,367"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Enables offline functionality","children":[],"payload":{"lines":"368,369"}},{"content":"Provides fast access to mappings","children":[],"payload":{"lines":"369,370"}},{"content":"Supports large numbers of mappings","children":[],"payload":{"lines":"370,372"}}],"payload":{"lines":"367,372"}}],"payload":{"lines":"365,372"}}],"payload":{"lines":"341,342"}},{"content":"Future Considerations","children":[{"content":"\n<p data-lines=\"374,375\"><strong>Performance Optimization</strong></p>","children":[{"content":"Implement pagination for large mapping sets","children":[],"payload":{"lines":"375,376"}},{"content":"Add caching for frequently used mappings","children":[],"payload":{"lines":"376,377"}},{"content":"Optimize database queries for faster lookups","children":[],"payload":{"lines":"377,379"}}],"payload":{"lines":"374,379"}},{"content":"\n<p data-lines=\"379,380\"><strong>Feature Enhancements</strong></p>","children":[{"content":"Add bulk import/export of mappings","children":[],"payload":{"lines":"380,381"}},{"content":"Implement mapping suggestions based on user patterns","children":[],"payload":{"lines":"381,382"}},{"content":"Add category statistics and insights","children":[],"payload":{"lines":"382,383"}},{"content":"Support for subcategories if needed","children":[],"payload":{"lines":"383,385"}}],"payload":{"lines":"379,385"}},{"content":"\n<p data-lines=\"385,386\"><strong>AI Improvements</strong></p>","children":[{"content":"Fine-tune AI categorization based on user corrections","children":[],"payload":{"lines":"386,387"}},{"content":"Add confidence scores for AI categorizations","children":[],"payload":{"lines":"387,388"}},{"content":"Implement batch processing for large datasets","children":[],"payload":{"lines":"388,390"}}],"payload":{"lines":"385,390"}}],"payload":{"lines":"372,373"}},{"content":"Validation and Testing","children":[{"content":"\n<p data-lines=\"392,393\"><strong>Category Mapping Tests</strong></p>","children":[{"content":"Verify case-insensitive matching","children":[],"payload":{"lines":"393,394"}},{"content":"Test duplicate handling","children":[],"payload":{"lines":"394,395"}},{"content":"Validate category constraints","children":[],"payload":{"lines":"395,397"}}],"payload":{"lines":"392,397"}},{"content":"\n<p data-lines=\"397,398\"><strong>AI Integration Tests</strong></p>","children":[{"content":"Test prompt effectiveness","children":[],"payload":{"lines":"398,399"}},{"content":"Verify category consistency","children":[],"payload":{"lines":"399,400"}},{"content":"Measure categorization accuracy","children":[],"payload":{"lines":"400,402"}}],"payload":{"lines":"397,402"}},{"content":"\n<p data-lines=\"402,403\"><strong>UI Testing</strong></p>","children":[{"content":"Verify responsive design","children":[],"payload":{"lines":"403,404"}},{"content":"Test accessibility features","children":[],"payload":{"lines":"404,405"}},{"content":"Validate user interaction flows","children":[],"payload":{"lines":"405,407"}}],"payload":{"lines":"402,407"}}],"payload":{"lines":"390,391"}}],"payload":{"lines":"279,280"}},{"content":"Current Application Features","children":[{"content":"Home Page","children":[{"content":"\n<p data-lines=\"410,411\"><strong>Recent Scans</strong></p>","children":[{"content":"Displays recently scanned receipts with detailed item information","children":[],"payload":{"lines":"411,412"}},{"content":"Shows category icons and names for each item","children":[],"payload":{"lines":"412,413"}},{"content":"Provides a clean, modern interface for viewing scanned items","children":[],"payload":{"lines":"413,415"}}],"payload":{"lines":"410,415"}},{"content":"\n<p data-lines=\"415,416\"><strong>Top Categories</strong></p>","children":[{"content":"Shows the most frequently occurring categories","children":[],"payload":{"lines":"416,417"}},{"content":"Displays category icons with corresponding colors","children":[],"payload":{"lines":"417,418"}},{"content":"Helps users track their shopping patterns","children":[],"payload":{"lines":"418,420"}}],"payload":{"lines":"415,420"}},{"content":"\n<p data-lines=\"420,421\"><strong>Upload Functionality</strong></p>","children":[{"content":"Allows users to scan and upload receipts","children":[],"payload":{"lines":"421,422"}},{"content":"Processes receipts using OCR and AI extraction","children":[],"payload":{"lines":"422,423"}},{"content":"Automatically categorizes items based on content","children":[],"payload":{"lines":"423,425"}}],"payload":{"lines":"420,425"}}],"payload":{"lines":"409,410"}},{"content":"Scanned Items Page","children":[{"content":"<strong>All Items View</strong>","children":[{"content":"Lists all scanned items chronologically","children":[],"payload":{"lines":"427,428"}},{"content":"Displays item name, category (with icon), and price","children":[],"payload":{"lines":"428,429"}},{"content":"Matches the home page styling for consistency","children":[],"payload":{"lines":"429,430"}},{"content":"Provides a comprehensive view of all scanned items","children":[],"payload":{"lines":"430,432"}}],"payload":{"lines":"426,432"}}],"payload":{"lines":"425,426"}},{"content":"Data Management","children":[{"content":"\n<p data-lines=\"433,434\"><strong>Local Database</strong></p>","children":[{"content":"Uses Dexie.js for IndexedDB management","children":[],"payload":{"lines":"434,435"}},{"content":"Stores items with categories and metadata","children":[],"payload":{"lines":"435,436"}},{"content":"Enables offline functionality","children":[],"payload":{"lines":"436,438"}}],"payload":{"lines":"433,438"}},{"content":"\n<p data-lines=\"438,439\"><strong>Category System</strong></p>","children":[{"content":"Predefined categories with custom icons","children":[],"payload":{"lines":"439,440"}},{"content":"Color-coded category indicators","children":[],"payload":{"lines":"440,441"}},{"content":"Consistent category display across all views","children":[],"payload":{"lines":"441,443"}}],"payload":{"lines":"438,443"}}],"payload":{"lines":"432,433"}},{"content":"User Interface","children":[{"content":"\n<p data-lines=\"444,445\"><strong>Navigation</strong></p>","children":[{"content":"Bottom navigation bar for easy access","children":[],"payload":{"lines":"445,446"}},{"content":"Intuitive icons for different sections","children":[],"payload":{"lines":"446,447"}},{"content":"Responsive design for mobile use","children":[],"payload":{"lines":"447,449"}}],"payload":{"lines":"444,449"}},{"content":"\n<p data-lines=\"449,450\"><strong>Styling</strong></p>","children":[{"content":"Modern, clean interface","children":[],"payload":{"lines":"450,451"}},{"content":"Consistent color scheme","children":[],"payload":{"lines":"451,452"}},{"content":"Backdrop blur effects for visual appeal","children":[],"payload":{"lines":"452,453"}},{"content":"Proper spacing and padding throughout","children":[],"payload":{"lines":"453,455"}}],"payload":{"lines":"449,455"}}],"payload":{"lines":"443,444"}},{"content":"AI Integration","children":[{"content":"\n<p data-lines=\"456,457\"><strong>Receipt Processing</strong></p>","children":[{"content":"OCR for text extraction","children":[],"payload":{"lines":"457,458"}},{"content":"AI-powered item categorization","children":[],"payload":{"lines":"458,459"}},{"content":"Smart total validation","children":[],"payload":{"lines":"459,461"}}],"payload":{"lines":"456,461"}},{"content":"\n<p data-lines=\"461,462\"><strong>Data Extraction</strong></p>","children":[{"content":"Intelligent item name parsing","children":[],"payload":{"lines":"462,463"}},{"content":"Price extraction and validation","children":[],"payload":{"lines":"463,464"}},{"content":"Category suggestion based on item content","children":[],"payload":{"lines":"464,466"}}],"payload":{"lines":"461,466"}}],"payload":{"lines":"455,456"}}],"payload":{"lines":"407,408"}},{"content":"Recent Decisions and Updates","children":[{"content":"Receipt Parsing Logic Enhancements","children":[{"content":"\n<p data-lines=\"469,470\"><strong>Case-Insensitive String Comparisons</strong>: Implemented case-insensitive checks for store names and other string comparisons to improve parsing accuracy.</p>","children":[],"payload":{"lines":"469,471"}},{"content":"\n<p data-lines=\"471,472\"><strong>Partial Success Logic</strong>: Added a mechanism to handle partial success in receipt parsing. If the sum of extracted item prices differs from the total amount, a warning message is logged to inform the user to review the items for completeness.</p>","children":[],"payload":{"lines":"471,473"}},{"content":"\n<p data-lines=\"473,474\"><strong>Item Extraction Improvements</strong>: Enhanced the item extraction logic to better capture item names and prices from various receipt formats. This includes refining regex patterns and handling different formats in the raw text.</p>","children":[],"payload":{"lines":"473,475"}},{"content":"\n<p data-lines=\"475,476\"><strong>Logging Enhancements</strong>: Added structured logging for extracted details, including store name, total amount, store address, and items. Each log entry is tagged with <code>[ALDI_RECEIPT]</code> for easier filtering.</p>","children":[],"payload":{"lines":"475,477"}},{"content":"\n<p data-lines=\"477,478\"><strong>Invalid Item Handling</strong>: Updated the validation logic to allow for partial successes. Invalid items are logged without failing the entire receipt processing, enabling users to see which items may need correction.</p>","children":[],"payload":{"lines":"477,479"}}],"payload":{"lines":"468,469"}},{"content":"Future Considerations","children":[{"content":"<strong>Further Refinement of Regex Patterns</strong>: Continue to refine regex patterns used for item extraction to accommodate more variations in receipt formats.","children":[],"payload":{"lines":"480,481"}},{"content":"<strong>User Interface Updates</strong>: Consider adding UI elements to allow users to manually edit or confirm extracted items when discrepancies are detected.","children":[],"payload":{"lines":"481,483"}}],"payload":{"lines":"479,480"}}],"payload":{"lines":"466,467"}},{"content":"Testing and Validation","children":[{"content":"Create unit tests for each parser to ensure they handle various receipt formats and edge cases correctly.","children":[],"payload":{"lines":"484,485"}},{"content":"Validate output against known correct data to ensure accuracy.","children":[],"payload":{"lines":"485,487"}}],"payload":{"lines":"483,484"}},{"content":"Documentation and Maintenance","children":[{"content":"Document each parser's functionality, including specific patterns or rules used for extraction.","children":[],"payload":{"lines":"488,489"}},{"content":"Keep parsers updated as supermarkets may change their receipt formats over time.","children":[],"payload":{"lines":"489,491"}}],"payload":{"lines":"487,488"}},{"content":"Receipt Image Management","children":[{"content":"Overview","children":[],"payload":{"lines":"493,494"}},{"content":"Core Components","children":[{"content":"\n<p data-lines=\"498,499\"><strong>Image Service</strong></p>\n<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">class</span> <span class=\"hljs-title class_\">ImageService</span> {\n <span class=\"hljs-keyword\">async</span> <span class=\"hljs-title function_\">processImage</span>(<span class=\"hljs-attr\">file</span>: <span class=\"hljs-title class_\">File</span>, <span class=\"hljs-attr\">options</span>: <span class=\"hljs-title class_\">ImageProcessingOptions</span>): <span class=\"hljs-title class_\">Promise</span><<span class=\"hljs-title class_\">ProcessedImage</span>>;\n <span class=\"hljs-keyword\">async</span> <span class=\"hljs-title function_\">createThumbnail</span>(<span class=\"hljs-attr\">file</span>: <span class=\"hljs-title class_\">File</span>): <span class=\"hljs-title class_\">Promise</span><<span class=\"hljs-title class_\">ProcessedImage</span>>;\n <span class=\"hljs-keyword\">async</span> <span class=\"hljs-title function_\">storeReceiptImage</span>(<span class=\"hljs-attr\">receiptId</span>: <span class=\"hljs-built_in\">number</span>, <span class=\"hljs-attr\">file</span>: <span class=\"hljs-title class_\">File</span>): <span class=\"hljs-title class_\">Promise</span><<span class=\"hljs-built_in\">number</span>>;\n <span class=\"hljs-keyword\">async</span> <span class=\"hljs-title function_\">getReceiptImage</span>(<span class=\"hljs-attr\">receiptId</span>: <span class=\"hljs-built_in\">number</span>): <span class=\"hljs-title class_\">Promise</span><{<span class=\"hljs-attr\">original</span>: <span class=\"hljs-title class_\">Blob</span>; <span class=\"hljs-attr\">thumbnail</span>: <span class=\"hljs-title class_\">Blob</span>} | <span class=\"hljs-literal\">null</span>>;\n}\n</code></pre>","children":[{"content":"Singleton service pattern","children":[],"payload":{"lines":"507,508"}},{"content":"Image processing and optimization","children":[],"payload":{"lines":"508,509"}},{"content":"Storage management","children":[],"payload":{"lines":"509,510"}},{"content":"Memory efficiency","children":[],"payload":{"lines":"510,512"}}],"payload":{"lines":"498,512"}},{"content":"\n<p data-lines=\"512,513\"><strong>Data Structure</strong></p>\n<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">interface</span> <span class=\"hljs-title class_\">ReceiptImage</span> {\n id?: <span class=\"hljs-built_in\">number</span>;\n <span class=\"hljs-attr\">receiptId</span>: <span class=\"hljs-built_in\">number</span>;\n <span class=\"hljs-attr\">originalImage</span>: <span class=\"hljs-title class_\">Blob</span>;\n <span class=\"hljs-attr\">thumbnailImage</span>: <span class=\"hljs-title class_\">Blob</span>;\n <span class=\"hljs-attr\">mimeType</span>: <span class=\"hljs-built_in\">string</span>;\n <span class=\"hljs-attr\">size</span>: <span class=\"hljs-built_in\">number</span>;\n <span class=\"hljs-attr\">createdAt</span>: <span class=\"hljs-title class_\">Date</span>;\n}\n</code></pre>","children":[{"content":"Separate storage from receipt data","children":[],"payload":{"lines":"524,525"}},{"content":"Multiple image versions","children":[],"payload":{"lines":"525,526"}},{"content":"Metadata tracking","children":[],"payload":{"lines":"526,527"}},{"content":"Efficient querying","children":[],"payload":{"lines":"527,529"}}],"payload":{"lines":"512,529"}},{"content":"\n<p data-lines=\"529,530\"><strong>UI Components</strong></p>\n<pre><code class=\"language-typescript\"><span class=\"hljs-keyword\">interface</span> <span class=\"hljs-title class_\">ReceiptImageViewerProps</span> {\n <span class=\"hljs-attr\">receiptId</span>: <span class=\"hljs-built_in\">number</span>;\n <span class=\"hljs-attr\">open</span>: <span class=\"hljs-built_in\">boolean</span>;\n <span class=\"hljs-attr\">onClose</span>: <span class=\"hljs-function\">() =></span> <span class=\"hljs-built_in\">void</span>;\n}\n</code></pre>","children":[{"content":"Modal image viewer","children":[],"payload":{"lines":"537,538"}},{"content":"Thumbnail previews","children":[],"payload":{"lines":"538,539"}},{"content":"Loading states","children":[],"payload":{"lines":"539,540"}},{"content":"Error handling","children":[],"payload":{"lines":"540,542"}}],"payload":{"lines":"529,542"}}],"payload":{"lines":"496,497"}},{"content":"Processing Pipeline","children":[{"content":"\n<p data-lines=\"544,545\"><strong>Image Upload</strong></p>","children":[{"content":"File validation","children":[],"payload":{"lines":"545,546"}},{"content":"Type checking","children":[],"payload":{"lines":"546,547"}},{"content":"Size verification","children":[],"payload":{"lines":"547,548"}},{"content":"Initial metadata extraction","children":[],"payload":{"lines":"548,550"}}],"payload":{"lines":"544,550"}},{"content":"\n<p data-lines=\"550,551\"><strong>Image Processing</strong></p>","children":[{"content":"Resolution optimization","children":[],"payload":{"lines":"551,552"}},{"content":"Quality adjustment","children":[],"payload":{"lines":"552,553"}},{"content":"Thumbnail generation","children":[],"payload":{"lines":"553,554"}},{"content":"Format conversion","children":[],"payload":{"lines":"554,556"}}],"payload":{"lines":"550,556"}},{"content":"\n<p data-lines=\"556,557\"><strong>Storage Management</strong></p>","children":[{"content":"Blob storage","children":[],"payload":{"lines":"557,558"}},{"content":"IndexedDB integration","children":[],"payload":{"lines":"558,559"}},{"content":"Version control","children":[],"payload":{"lines":"559,560"}},{"content":"Cleanup routines","children":[],"payload":{"lines":"560,562"}}],"payload":{"lines":"556,562"}}],"payload":{"lines":"542,543"}},{"content":"Design Decisions","children":[{"content":"\n<p data-lines=\"564,565\"><strong>Multi-Version Storage</strong></p>","children":[{"content":"<strong>Decision</strong>: Store both original and optimized versions","children":[],"payload":{"lines":"565,566"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Fast thumbnail loading","children":[],"payload":{"lines":"567,568"}},{"content":"High-quality viewing when needed","children":[],"payload":{"lines":"568,569"}},{"content":"Bandwidth optimization","children":[],"payload":{"lines":"569,570"}},{"content":"Better mobile experience","children":[],"payload":{"lines":"570,572"}}],"payload":{"lines":"566,572"}}],"payload":{"lines":"564,572"}},{"content":"\n<p data-lines=\"572,573\"><strong>Blob Storage</strong></p>","children":[{"content":"<strong>Decision</strong>: Use Blob storage over base64","children":[],"payload":{"lines":"573,574"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"33% smaller storage footprint","children":[],"payload":{"lines":"575,576"}},{"content":"Better memory efficiency","children":[],"payload":{"lines":"576,577"}},{"content":"Native browser handling","children":[],"payload":{"lines":"577,578"}},{"content":"Improved performance","children":[],"payload":{"lines":"578,580"}}],"payload":{"lines":"574,580"}}],"payload":{"lines":"572,580"}},{"content":"\n<p data-lines=\"580,581\"><strong>Separate Storage</strong></p>","children":[{"content":"<strong>Decision</strong>: Dedicated table for images","children":[],"payload":{"lines":"581,582"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Better query performance","children":[],"payload":{"lines":"583,584"}},{"content":"Simplified backup strategy","children":[],"payload":{"lines":"584,585"}},{"content":"Easier maintenance","children":[],"payload":{"lines":"585,586"}},{"content":"Future extensibility","children":[],"payload":{"lines":"586,588"}}],"payload":{"lines":"582,588"}}],"payload":{"lines":"580,588"}},{"content":"\n<p data-lines=\"588,589\"><strong>Canvas Processing</strong></p>","children":[{"content":"<strong>Decision</strong>: Use Canvas API for image processing","children":[],"payload":{"lines":"589,590"}},{"content":"<strong>Rationale</strong>:","children":[{"content":"Client-side optimization","children":[],"payload":{"lines":"591,592"}},{"content":"Real-time preview","children":[],"payload":{"lines":"592,593"}},{"content":"Quality control","children":[],"payload":{"lines":"593,594"}},{"content":"Format flexibility","children":[],"payload":{"lines":"594,596"}}],"payload":{"lines":"590,596"}}],"payload":{"lines":"588,596"}}],"payload":{"lines":"562,563"}},{"content":"Performance Optimizations","children":[{"content":"\n<p data-lines=\"598,599\"><strong>Loading Strategy</strong></p>","children":[{"content":"Lazy loading for thumbnails","children":[],"payload":{"lines":"599,600"}},{"content":"Progressive loading for originals","children":[],"payload":{"lines":"600,601"}},{"content":"Memory management","children":[],"payload":{"lines":"601,602"}},{"content":"Cache utilization","children":[],"payload":{"lines":"602,604"}}],"payload":{"lines":"598,604"}},{"content":"\n<p data-lines=\"604,605\"><strong>Resource Management</strong></p>","children":[{"content":"URL object cleanup","children":[],"payload":{"lines":"605,606"}},{"content":"Memory monitoring","children":[],"payload":{"lines":"606,607"}},{"content":"Batch processing","children":[],"payload":{"lines":"607,608"}},{"content":"Background operations","children":[],"payload":{"lines":"608,610"}}],"payload":{"lines":"604,610"}}],"payload":{"lines":"596,597"}},{"content":"Error Handling","children":[{"content":"\n<p data-lines=\"612,613\"><strong>Upload Validation</strong></p>","children":[{"content":"File type verification","children":[],"payload":{"lines":"613,614"}},{"content":"Size constraints","children":[],"payload":{"lines":"614,615"}},{"content":"Format validation","children":[],"payload":{"lines":"615,616"}},{"content":"Corruption detection","children":[],"payload":{"lines":"616,618"}}],"payload":{"lines":"612,618"}},{"content":"\n<p data-lines=\"618,619\"><strong>Processing Errors</strong></p>","children":[{"content":"Fallback strategies","children":[],"payload":{"lines":"619,620"}},{"content":"User notifications","children":[],"payload":{"lines":"620,621"}},{"content":"Recovery options","children":[],"payload":{"lines":"621,622"}},{"content":"Logging and monitoring","children":[],"payload":{"lines":"622,624"}}],"payload":{"lines":"618,624"}}],"payload":{"lines":"610,611"}},{"content":"User Experience","children":[{"content":"\n<p data-lines=\"626,627\"><strong>Viewing Features</strong></p>","children":[{"content":"Smooth transitions","children":[],"payload":{"lines":"627,628"}},{"content":"Loading indicators","children":[],"payload":{"lines":"628,629"}},{"content":"Error messages","children":[],"payload":{"lines":"629,630"}},{"content":"Progress feedback","children":[],"payload":{"lines":"630,632"}}],"payload":{"lines":"626,632"}},{"content":"\n<p data-lines=\"632,633\"><strong>Interaction Design</strong></p>","children":[{"content":"Intuitive controls","children":[],"payload":{"lines":"633,634"}},{"content":"Responsive layout","children":[],"payload":{"lines":"634,635"}},{"content":"Touch support","children":[],"payload":{"lines":"635,636"}},{"content":"Accessibility","children":[],"payload":{"lines":"636,638"}}],"payload":{"lines":"632,638"}}],"payload":{"lines":"624,625"}},{"content":"Future Enhancements","children":[{"content":"\n<p data-lines=\"640,641\"><strong>Image Features</strong></p>","children":[{"content":"Rotation controls","children":[],"payload":{"lines":"641,642"}},{"content":"Zoom capabilities","children":[],"payload":{"lines":"642,643"}},{"content":"Cropping tools","children":[],"payload":{"lines":"643,644"}},{"content":"Filter options","children":[],"payload":{"lines":"644,646"}}],"payload":{"lines":"640,646"}},{"content":"\n<p data-lines=\"646,647\"><strong>Storage Options</strong></p>","children":[{"content":"Cloud backup","children":[],"payload":{"lines":"647,648"}},{"content":"Compression improvements","children":[],"payload":{"lines":"648,649"}},{"content":"Format optimization","children":[],"payload":{"lines":"649,650"}},{"content":"Archive functionality","children":[],"payload":{"lines":"650,652"}}],"payload":{"lines":"646,652"}}],"payload":{"lines":"638,639"}},{"content":"Testing Requirements","children":[{"content":"\n<p data-lines=\"654,655\"><strong>Unit Tests</strong></p>","children":[{"content":"Processing functions","children":[],"payload":{"lines":"655,656"}},{"content":"Storage operations","children":[],"payload":{"lines":"656,657"}},{"content":"Error handling","children":[],"payload":{"lines":"657,658"}},{"content":"UI components","children":[],"payload":{"lines":"658,660"}}],"payload":{"lines":"654,660"}},{"content":"\n<p data-lines=\"660,661\"><strong>Integration Tests</strong></p>","children":[{"content":"Upload workflow","children":[],"payload":{"lines":"661,662"}},{"content":"Display functionality","children":[],"payload":{"lines":"662,663"}},{"content":"Error scenarios","children":[],"payload":{"lines":"663,664"}},{"content":"Performance metrics","children":[],"payload":{"lines":"664,666"}}],"payload":{"lines":"660,666"}}],"payload":{"lines":"652,653"}},{"content":"Security Considerations","children":[{"content":"\n<p data-lines=\"668,669\"><strong>Upload Security</strong></p>","children":[{"content":"File validation","children":[],"payload":{"lines":"669,670"}},{"content":"Size limits","children":[],"payload":{"lines":"670,671"}},{"content":"Type restrictions","children":[],"payload":{"lines":"671,672"}},{"content":"Sanitization","children":[],"payload":{"lines":"672,674"}}],"payload":{"lines":"668,674"}},{"content":"\n<p data-lines=\"674,675\"><strong>Storage Security</strong></p>","children":[{"content":"Access control","children":[],"payload":{"lines":"675,676"}},{"content":"Data encryption","children":[],"payload":{"lines":"676,677"}},{"content":"Secure deletion","children":[],"payload":{"lines":"677,678"}},{"content":"Privacy compliance","children":[],"payload":{"lines":"678,680"}}],"payload":{"lines":"674,680"}}],"payload":{"lines":"666,667"}}],"payload":{"lines":"491,492"}},{"content":"Conclusion","children":[],"payload":{"lines":"680,681"}},{"content":"Conclusion","children":[],"payload":{"lines":"683,684"}}],"payload":{"lines":"0,1"}},{})</script>
</body>
</html>