Expert guidance for developing and maintaining SoExpensive, a Finnish supermarket price comparison web app. Helps with database operations, CSV imports, performance optimization, and deployment on Vercel while maintaining the terminal aesthetic.
Expert assistance for developing and maintaining SoExpensive, a Finnish supermarket price comparison web application built with Node.js, Express, PostgreSQL, and vanilla JavaScript.
This skill provides comprehensive guidance for working on the SoExpensive project, including:
**Live Site:** https://soexpensive.jaime.win
**Tech Stack:** Node.js + Express + PostgreSQL (Vercel) + Vanilla JS
**Git Branch:** `claude/price-comparison-app-km6Wj`
**Design:** Monospace terminal aesthetic (JetBrains Mono font, ASCII art)
**Performance Targets:** LCP <1s, CLS 0, INP <40ms
**Stores Tracked:** S-Market, Prisma, K-Citymarket, K-Supermarket, Lidl, Alepa
1. **No paid services** - Free tier only (Vercel free tier)
2. **No manual data entry** - Automation required
3. **Maintain terminal aesthetic** - Monospace fonts, ASCII charts, no modern UI patterns
4. **Maintain performance** - Keep LCP, CLS, INP metrics excellent
5. **Price precision** - Store prices as INTEGER cents, never floats
**Schema Structure:**
**Critical Issue - Price History:**
The current `UNIQUE(product_id, store_id)` constraint on the prices table blocks historical price tracking. When modifying the schema:
**Database Operations:**
```javascript
// Initialize database (creates tables)
await db.initDatabase();
// Check database status
const hasData = await db.isDatabaseInitialized();
// Seed sample data
node seed.js // or GET /api/seed
// Cleanup (dangerous - no confirmation)
POST /api/cleanup
```
**Current CSV Format (prices.csv):**
```csv
product_name,price_cents,store_name,updated
Maito,99,K-Citymarket,2025-12-28
```
**User's Scraped Format (needs parser):**
```
PRODUCT NAME | PRICE (€/unit) | PRICE (€/kg)
Pirkka banaani | 0.30 | 1.69
```
**Import Process:**
1. Parse CSV data (handle both comma and pipe delimiters)
2. Normalize Finnish characters (å, ä, ö)
3. Use fuzzy matching to find products in database
4. Convert euro values to cents: `Math.round(euros * 100)`
5. Insert via `/api/import-prices` endpoint
6. Return detailed success/failure counts
**Fuzzy Matching Pattern:**
```javascript
function normalizeProductName(name) {
return name.toLowerCase()
.replace(/[^\wåäö\s]/g, '')
.trim();
}
```
**Must Maintain Metrics:**
**Optimization Techniques:**
**Testing Performance:**
**Monospace Terminal Aesthetic - MUST MAINTAIN:**
DO:
DO NOT:
**Git Strategy:**
```bash
git add .
git commit -m "Description of changes"
git push -u origin claude/price-comparison-app-km6Wj
```
**Vercel Configuration:**
**Public Endpoints:**
**Current Status:**
**Approaches:**
1. **Manual CSV Collection** ✅ Current approach for K-Citymarket
2. **Web Scraping** ❌ Blocked by stores, timeout issues
3. **Claude Browser Extension** 🔄 Being explored by user
**When Adding New Data:**
**Project Structure:**
```
api/ # Vercel serverless functions
public/ # Static frontend (HTML/CSS/JS)
server.js # Express app (171 lines)
db.js # PostgreSQL layer (204 lines)
seed.js # Seeding script (224 lines)
prices.csv # Real K-Citymarket data
```
**Patterns to Follow:**
**When Making Changes:**
1. Read existing code first
2. Test locally before deploying
3. Verify performance metrics maintained
4. Check terminal aesthetic preserved
5. Commit with clear message
6. Push to trigger auto-deploy
**Scenario 1: Import New Price Data**
```bash
```
**Scenario 2: Enable Price History**
```sql
-- Remove UNIQUE constraint
ALTER TABLE prices DROP CONSTRAINT prices_product_id_store_id_key;
-- Update queries to get latest price
SELECT * FROM prices
WHERE product_id = $1 AND store_id = $2
ORDER BY recorded_at DESC LIMIT 1;
```
**Scenario 3: Add New Feature (Admin CSV Upload)**
```javascript
// 1. Add upload form to admin.html (maintain monospace aesthetic)
// 2. Create /api/upload-csv endpoint
// 3. Parse CSV server-side (support both formats)
// 4. Use existing import logic
// 5. Test performance impact
// 6. Deploy
```
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/finnish-supermarket-price-comparison/raw