Step-by-Step Plan
Create "Weekend Plans :
1. Based on Distance (user location as reference)
- insert Location toggle button
- Implement a way for user to set his location Worldwide.
- The Search for Weekend Plans is based on User Location setting.
Search Results :
-
** Implement a way for the User to set the Search Location"
-
**The Search Results Should display according to the Distance from tbe User's
Location: if the user's location distance to the search location is bigger than 30 kms
The Search must show Public Transportation Options.
If the same distance is bigger than 300 kms, Plane's transportation options should
be displayed.
Displaying Transportation, Hosting options (according to the budget), Restaurant's options
plus cost with local transportation (taxis, uber, bus, metro)
-
The search should return 10 Results
-
The Results should output different Places
Results Breakdown
- **If the Distance from user's Location to
1) Create "Weekend Plans
Why: Deterministic behavior offline; easy overrides via YAML/env.
Files to add/modify
app/utils/cache.py: TTL JSON file cache under ~/.weekend-planner/cache/
app/utils/env_loader.py: merge defaults → YAML → ENV (tokens)
app/utils/http.py: lightweight GET with retries/backoff (used only when online)
Acceptance
- Can
import all three modules.
cache.set/get round-trip a dict; TTL respected.
2) Implement FX connector with fallbacks
Why: Pivot all costs to user currency even offline.
Files
app/connectors/fx.py:
- Order: TTL
cache → live API → last_good (no TTL) → builtin rates {"EUR":1.0,"USD":1.08,"GBP":0.85}
- Expose
get_fx_rates() and get_fx_rates_with_meta() (returns (rates, source, cache_hit))
Acceptance
- Offline: returns builtin/last_good and sets
source to "builtin" or "last_good".
- Online: first run
"live", subsequent runs hit "cache" within 24h.
3) Implement vendor connectors with offline dummy data
Why: Ensure local, no-network runs succeed.
Files
data/dummy/offers_vendor_a.json
data/dummy/offers_vendor_b.json
app/connectors/ticket_vendor_a.py, ticket_vendor_b.py:
- If no
VENDOR_*_TOKEN, load dummy JSON and hydrate title/start_ts/venue from the query.
- Normalized shape per offer:
{
"provider": "a|b",
"price": {"amount": 22.0, "currency": "EUR", "includes_vat": true},
"fees": [{"type":"service","amount":2.5,"currency":"EUR"}],
"vat_rate": 0.23,
"promos": ["CODE"],
"inventory_hint": "low|med|high",
"url": "https://…"
}
Acceptance
- Without tokens, each connector returns ≥1 normalized offer from local JSON.
4) Add optional dining connector (offline stub)
Files
app/connectors/dining.py: return one static nearby suggestion offline (e.g., “Taberna X” with est_pp).
Acceptance
- When asked for dining, returns a small list; otherwise omitted.
5) Implement landed-cost normalization (transparent pricing)
Files
app/normalizers/price.py:
- Inputs: offer,
user_cur, fx_rates, vat_fallback, promo_rules
- Output:
(landed, breakdown) where:
landed: {amount, currency}
breakdown: {base, fees, vat, promo, fx} (all rounded to 0.01)
Acceptance
- VAT included →
vat=0.
- VAT excluded → apply
vat_fallback if vat_rate is None.
- Percent vs fixed promos → choose best single promo.
6) Add multi-vendor reconciliation
Files
app/reconcile/merge.py: group offers by (title,start_ts); keep lowest landed; attach provenance array with each vendor’s landed + URL.
Acceptance
- Multiple offers for the same event return one item with
provenance ≥2.
7) Price-drop classifier (optional) + buy-now policy
Files
app/models/price_drop/features.py: rolling min/std over a series (stub OK)
app/models/price_drop/policy.py:
predict_prob(series) loads model if present; else simple heuristic using inventory_hint.
buy_now_policy(prob, days_to_event, threshold, min_days_force_buy).
Acceptance
- If model file missing, function still returns a probability in
[0,1].
buy_now_policy flips to True when close to event or very low inventory.
8) Budget-aware scoring
Files
app/ranking/scorer.py:
- Penalize over-budget, add slight penalty for total cost incl. dining, add small bonus if price likely to drop and there’s time.
Acceptance
- Higher scores for within-budget options; tie-breakers behave sensibly.
9) CLI pipeline
Files
app/main.py:
- Build a single event query for a given date/city.
- Fetch offers from both vendors.
- Compute landed + breakdown, predict drop prob, compute
buy_now, optionally add dining, compute score.
- Reconcile multi-vendor, sort by score, print top 1–3 itineraries as JSON.
Acceptance
- Offline run prints valid itineraries JSON with fields:
event_title, start_ts, best_price:{landed,breakdown,provider,price_drop_prob_7d,buy_now,url}, meal_bundle, score, provenance (after reconcile).
10) Minimal API (optional)
Files
app/server.py with GET /plan?date=YYYY-MM-DD&budget=35&with_dining=true.
- Returns same schema as CLI; may embed small HTML tester page.
Acceptance
- Local call returns JSON; includes an
fx_source field for visibility.
11) Tests (must pass offline)
Files
tests/test_landed_cost.py: VAT-included, VAT-excluded, percent vs fixed promo, FX pivot USD→EUR.
tests/test_reconcile.py: ensures best landed wins, provenance attached.
Acceptance
pytest -q passes without internet or tokens.
Configuration
app/config/settings.example.yaml
currency: "EUR"
pricing.vat_fallback_rate
pricing.promo_rules (e.g., STUDENT10, LOYALTY5)
model.price_drop_threshold, model.min_days_force_buy
apis.fx.base_url
- ENV overrides (optional):
VENDOR_A_TOKEN, VENDOR_B_TOKEN, DINING_TOKEN.
Deliverables Checklist
- Offline-capable connectors (FX + vendors + dining stub).
- Landed-cost math with per-offer transparent breakdown.
- Reconciliation across vendors with
provenance.
- Buy-now policy + budget-aware scoring.
- CLI that prints itineraries JSON.
- (Optional) API endpoint.
- Dummy dataset under
data/dummy/.
- Passing tests (VAT/fees/promo/FX/reconcile/score).
- Updated README explaining setup, offline mode, and how to extend.
Verification (Offline)
- Disconnect network (or block outbound).
- Ensure no tokens are set.
- Run CLI for a date; expect valid JSON with
fx_source = builtin/last_good.
- Run tests; expect all green.
Notes & Constraints
- Keep third-party deps minimal; offline behavior must not import heavy clients except when available.
- Do not remove or rewrite existing modules outside the scope above; add new modules or extend in place.
- All money math rounded to 2 decimals in the breakdown + landed total.
Step-by-Step Plan
Create "Weekend Plans :
1. Based on Distance (user location as reference)
Search Results :
** Implement a way for the User to set the Search Location"
**The Search Results Should display according to the Distance from tbe User's
Location: if the user's location distance to the search location is bigger than 30 kms
The Search must show Public Transportation Options.
If the same distance is bigger than 300 kms, Plane's transportation options should
be displayed.
Displaying Transportation, Hosting options (according to the budget), Restaurant's options
plus cost with local transportation (taxis, uber, bus, metro)
The search should return 10 Results
The Results should output different Places
Results Breakdown
1) Create "Weekend Plans
Why: Deterministic behavior offline; easy overrides via YAML/env.
Files to add/modify
app/utils/cache.py: TTL JSON file cache under~/.weekend-planner/cache/app/utils/env_loader.py: merge defaults → YAML → ENV (tokens)app/utils/http.py: lightweight GET with retries/backoff (used only when online)Acceptance
importall three modules.cache.set/getround-trip a dict; TTL respected.2) Implement FX connector with fallbacks
Why: Pivot all costs to user currency even offline.
Files
app/connectors/fx.py:cache→ live API →last_good(no TTL) → builtin rates{"EUR":1.0,"USD":1.08,"GBP":0.85}get_fx_rates()andget_fx_rates_with_meta()(returns(rates, source, cache_hit))Acceptance
sourceto"builtin"or"last_good"."live", subsequent runs hit"cache"within 24h.3) Implement vendor connectors with offline dummy data
Why: Ensure local, no-network runs succeed.
Files
data/dummy/offers_vendor_a.jsondata/dummy/offers_vendor_b.jsonapp/connectors/ticket_vendor_a.py,ticket_vendor_b.py:VENDOR_*_TOKEN, load dummy JSON and hydratetitle/start_ts/venuefrom the query.{ "provider": "a|b", "price": {"amount": 22.0, "currency": "EUR", "includes_vat": true}, "fees": [{"type":"service","amount":2.5,"currency":"EUR"}], "vat_rate": 0.23, "promos": ["CODE"], "inventory_hint": "low|med|high", "url": "https://…" }Acceptance
4) Add optional dining connector (offline stub)
Files
app/connectors/dining.py: return one static nearby suggestion offline (e.g., “Taberna X” withest_pp).Acceptance
5) Implement landed-cost normalization (transparent pricing)
Files
app/normalizers/price.py:user_cur,fx_rates,vat_fallback,promo_rules(landed, breakdown)where:landed:{amount, currency}breakdown:{base, fees, vat, promo, fx}(all rounded to 0.01)Acceptance
vat=0.vat_fallbackifvat_rateisNone.6) Add multi-vendor reconciliation
Files
app/reconcile/merge.py: group offers by(title,start_ts); keep lowest landed; attachprovenancearray with each vendor’s landed + URL.Acceptance
provenance≥2.7) Price-drop classifier (optional) + buy-now policy
Files
app/models/price_drop/features.py: rolling min/std over a series (stub OK)app/models/price_drop/policy.py:predict_prob(series)loads model if present; else simple heuristic usinginventory_hint.buy_now_policy(prob, days_to_event, threshold, min_days_force_buy).Acceptance
[0,1].buy_now_policyflips toTruewhen close to event or very low inventory.8) Budget-aware scoring
Files
app/ranking/scorer.py:Acceptance
9) CLI pipeline
Files
app/main.py:buy_now, optionally add dining, compute score.Acceptance
event_title,start_ts,best_price:{landed,breakdown,provider,price_drop_prob_7d,buy_now,url},meal_bundle,score,provenance(after reconcile).10) Minimal API (optional)
Files
app/server.pywithGET /plan?date=YYYY-MM-DD&budget=35&with_dining=true.Acceptance
fx_sourcefield for visibility.11) Tests (must pass offline)
Files
tests/test_landed_cost.py: VAT-included, VAT-excluded, percent vs fixed promo, FX pivot USD→EUR.tests/test_reconcile.py: ensures best landed wins, provenance attached.Acceptance
pytest -qpasses without internet or tokens.Configuration
app/config/settings.example.yamlcurrency: "EUR"pricing.vat_fallback_ratepricing.promo_rules(e.g.,STUDENT10,LOYALTY5)model.price_drop_threshold,model.min_days_force_buyapis.fx.base_urlVENDOR_A_TOKEN,VENDOR_B_TOKEN,DINING_TOKEN.Deliverables Checklist
provenance.data/dummy/.Verification (Offline)
fx_source=builtin/last_good.Notes & Constraints