Add legal policy pages and shared layout component
- Add Cookie Policy view documenting essential cookies (session, CSRF, remember_me, fa_location) and cookieless Umami analytics - Add Privacy Policy view covering UK GDPR compliance, data categories, lawful bases, processors, retention, and user rights - Add Refund & Cancellation Policy view explaining 14-day cooling-off period under Consumer Contracts Regulations 2013 and express-consent flow - Add Terms of Service view defining account rules, subscription billing, and governing law - Create shared legal layout component with FuelAlert header, footer with cross-links, and consistent typography - Add feature tests covering all four legal pages and their cross-links - All policies include placeholders for ICO registration number, email, and hosting/email providers pending production config
This commit is contained in:
403
docs/superpowers/specs/legal-pages-spec.md
Normal file
403
docs/superpowers/specs/legal-pages-spec.md
Normal file
@@ -0,0 +1,403 @@
|
||||
# FuelAlert — Legal Pages Spec
|
||||
|
||||
## Context for Claude Code
|
||||
|
||||
You are generating four legal pages for **FuelAlert**, a UK consumer subscription web/mobile app that shows real-time UK fuel prices and forecasts.
|
||||
|
||||
### Reference comparable (structural check, NOT for copying)
|
||||
|
||||
A near-identical business already exists and has competent legal pages: **Fuel Finder UK** at https://www.fuel-finder.uk, operated by Scott Benson as a UK sole trader. Same business model, same data sources, same jurisdiction.
|
||||
|
||||
**Use it ONLY as a structural sanity check.** Do not copy any text. Their content is copyrighted and their specific processors / retention periods / business decisions are not FuelAlert's.
|
||||
|
||||
What Fuel Finder UK does well that this spec already incorporates:
|
||||
- Explicit sole trader disclosure naming the operator
|
||||
- Named ICO registration number in the Privacy Policy
|
||||
- Specific named processors (Stripe, hosting provider, email provider, analytics, mapping services) with what data flows to each
|
||||
- Strong price-accuracy disclaimer in Terms ("prices may not reflect real-time changes, always verify at the pump")
|
||||
- "AS IS" / "AS AVAILABLE" basis with liability limitations
|
||||
- ICO complaint route clearly stated
|
||||
- Account deletion flow that cancels paid subscription first
|
||||
|
||||
What FuelAlert must do BETTER than Fuel Finder UK:
|
||||
- **Standalone Refund & Cancellation Policy page** — Fuel Finder UK appears to bundle this into Terms. Stripe specifically asks for a refund policy; keep it as a separate page at `/legal/refund`.
|
||||
- **Express-consent checkbox at subscription checkout** for the 14-day cooling-off period under Consumer Contracts Regulations 2013 (see Refund Policy section below). This is the single most important implementation detail in the entire spec.
|
||||
|
||||
If you find yourself generating content that overlaps verbatim with Fuel Finder UK or any other site, stop and rewrite in your own words. Legal pages are copyrighted works.
|
||||
|
||||
**Business operator (data controller):**
|
||||
- Name: Ovidiu Ungureanu
|
||||
- Trading as: FuelAlert
|
||||
- Status: Sole trader (not a limited company — do not use "Ltd", "Limited", or any corporate form)
|
||||
- Location: Peterborough, United Kingdom
|
||||
- Contact email: [hello@fuelalert.co.uk]
|
||||
- ICO registration number: [PLACEHOLDER: ZAxxxxxxx — Ovidiu to register at ico.org.uk before launch, fee ~£40/yr]
|
||||
|
||||
**Service:**
|
||||
- UK fuel price comparison and forecasting
|
||||
- Free tier + two paid subscription tiers: Daily (£0.99/mo) and Smart (£2.49/mo); annual billing also offered
|
||||
- Data sources: UK government Fuel Finder / Pump Watch open data, ONS Postcode Directory (OGL/Crown Copyright)
|
||||
- Processes: email address, postcode/location data, account credentials, payment data (via Stripe), usage telemetry
|
||||
|
||||
**Jurisdiction:**
|
||||
- England and Wales
|
||||
- Consumer law: Consumer Rights Act 2015, Consumer Contracts (Information, Cancellation and Additional Charges) Regulations 2013 ("CCRs")
|
||||
- Data protection: UK GDPR + Data Protection Act 2018, PECR for cookies/marketing
|
||||
- Digital markets: Digital Markets, Competition and Consumers Act 2024 ("DMCC")
|
||||
|
||||
**Tech stack & integration:**
|
||||
- Laravel + Blade for server-rendered pages (NOT Vue components — these must render in raw HTML for Stripe reviewers and SEO)
|
||||
- Route prefix: `/legal/*`
|
||||
- Layout: extend the existing site layout but with a readable prose container (max-width ~720px, generous line-height)
|
||||
- Each page has a `last_updated` date in front matter — set to today
|
||||
- All pages must be linkable from the footer and accessible without JavaScript
|
||||
|
||||
### ⚠️ CRITICAL: Server-rendered Blade only, NOT Vue
|
||||
|
||||
The rest of this application is a Vue SPA. **That is irrelevant for these pages.** The legal pages must be server-rendered Blade templates.
|
||||
|
||||
Rules:
|
||||
- Files live at `resources/views/legal/{name}.blade.php` — never `.vue`
|
||||
- Body content must be plain HTML with Blade directives (`@extends`, `@section`, `{{ }}`)
|
||||
- No Vue components anywhere in the page body — no custom tags like `<legal-privacy-page>`, no `<div id="app">`, no Vue mounting points
|
||||
- No client-side rendering for the legal content itself — Alpine.js is acceptable only for the cookie banner show/hide behaviour, nothing else
|
||||
- Pages must work fully with JavaScript disabled
|
||||
|
||||
**Verification test (run after generation):**
|
||||
|
||||
```bash
|
||||
curl -s https://[host]/legal/privacy | grep -i "data controller"
|
||||
curl -s https://[host]/legal/terms | grep -i "subscription"
|
||||
curl -s https://[host]/legal/refund | grep -i "14-day"
|
||||
curl -s https://[host]/legal/cookies | grep -i "essential"
|
||||
```
|
||||
|
||||
Each command must return matching lines from the raw HTML response. If any returns empty, the page has been built as a client-rendered component and must be redone as Blade.
|
||||
|
||||
If you find yourself reaching for `<script>` tags, Vue single-file components, or any pattern that requires the browser to execute JS before content appears — stop and use plain Blade instead.
|
||||
|
||||
---
|
||||
|
||||
## Pages to generate
|
||||
|
||||
1. `/legal/privacy` — Privacy Policy
|
||||
2. `/legal/terms` — Terms of Service
|
||||
3. `/legal/refund` — Refund & Cancellation Policy (can be a section of Terms, but a separate page is cleaner for Stripe review)
|
||||
4. `/legal/cookies` — Cookie Policy (paired with a real consent banner — see separate section)
|
||||
|
||||
---
|
||||
|
||||
## 1. Privacy Policy (`/legal/privacy`)
|
||||
|
||||
### Required sections, in order:
|
||||
|
||||
**1. Who we are**
|
||||
- Identify Ovidiu Ungureanu as data controller, trading as FuelAlert
|
||||
- Sole trader status, Peterborough address (use generic "Peterborough, UK" unless a registered business address is provided)
|
||||
- ICO registration number
|
||||
- Contact email for privacy queries
|
||||
|
||||
**2. What data we collect**
|
||||
Break into clear subsections:
|
||||
- *Account data*: email, hashed password, account creation date
|
||||
- *Location data*: postcodes entered, optional precise GPS if granted, derived location for nearby-station queries
|
||||
- *Payment data*: handled by Stripe; FuelAlert does NOT store card numbers. Stripe customer ID and subscription metadata only.
|
||||
- *Usage data*: features used, queries made, price alerts configured (for service delivery and improvement)
|
||||
- *Technical data*: IP address, browser type, device type (for security and analytics)
|
||||
- *Marketing preferences*: only if user opts in
|
||||
|
||||
**3. Lawful basis for processing**
|
||||
For each category, state the UK GDPR Article 6 basis:
|
||||
- Account + service delivery: **contract** (Art. 6(1)(b))
|
||||
- Payment processing: **contract**
|
||||
- Security/fraud prevention: **legitimate interests** (Art. 6(1)(f))
|
||||
- Analytics/product improvement: **legitimate interests**, with opt-out via cookie banner
|
||||
- Marketing emails: **consent** (Art. 6(1)(a))
|
||||
|
||||
**4. How we use your data**
|
||||
Bullet list, plain English. Tie back to the lawful basis for each use.
|
||||
|
||||
**5. Who we share data with (processors)**
|
||||
Named list — be specific:
|
||||
- **Stripe** (payment processing) — refer to Stripe's privacy policy
|
||||
- **[Hosting provider, e.g. Hetzner]** (infrastructure) — EU-based, note location
|
||||
- **[Email provider, e.g. Fastmail / Postmark]** (transactional email)
|
||||
- **[Analytics, e.g. Plausible]** — if used; if self-hosted, say so
|
||||
- State that we do NOT sell data to third parties
|
||||
|
||||
**6. International transfers**
|
||||
- State whether any processors are outside the UK/EEA (Stripe has US operations)
|
||||
- Reference appropriate safeguards: Standard Contractual Clauses (SCCs) and UK International Data Transfer Addendum
|
||||
|
||||
**7. How long we keep data**
|
||||
- Active account data: while account is active + 12 months after closure
|
||||
- Payment records: 6 years (HMRC requirement for sole traders)
|
||||
- Marketing data: until consent is withdrawn
|
||||
- Logs/analytics: max 24 months
|
||||
|
||||
**8. Your rights under UK GDPR**
|
||||
List all eight rights with one-line explanations:
|
||||
- Right of access
|
||||
- Right to rectification
|
||||
- Right to erasure ("right to be forgotten")
|
||||
- Right to restrict processing
|
||||
- Right to data portability
|
||||
- Right to object
|
||||
- Rights related to automated decision-making (state we do NOT make solely automated decisions with legal effect)
|
||||
- Right to withdraw consent
|
||||
|
||||
Explain how to exercise rights (email to the contact address, response within one month).
|
||||
|
||||
**9. Cookies**
|
||||
Brief mention with link to the dedicated Cookie Policy.
|
||||
|
||||
**10. Security**
|
||||
Plain-English summary: HTTPS, hashed passwords, encrypted database fields where appropriate, access controls, regular updates. Don't overpromise ("bank-grade" etc. — meaningless and creates liability).
|
||||
|
||||
**11. Children**
|
||||
Service is not directed at under-16s; we do not knowingly collect data from children.
|
||||
|
||||
**12. Complaints**
|
||||
Right to complain to the ICO: ico.org.uk, 0303 123 1113. Encourage contacting FuelAlert first.
|
||||
|
||||
**13. Changes to this policy**
|
||||
We will notify users of material changes by email; non-material changes shown by updated "Last updated" date.
|
||||
|
||||
**14. Contact**
|
||||
Email address for privacy queries.
|
||||
|
||||
### Tone & style
|
||||
- Plain English, Hemingway readability score ~grade 8
|
||||
- No legalese where avoidable
|
||||
- Use "we" / "you"
|
||||
- Short paragraphs, lots of headings, scannable
|
||||
|
||||
---
|
||||
|
||||
## 2. Terms of Service (`/legal/terms`)
|
||||
|
||||
### Required sections, in order:
|
||||
|
||||
**1. About these terms**
|
||||
- Who FuelAlert is (sole trader disclosure)
|
||||
- These terms form a contract between you and Ovidiu Ungureanu trading as FuelAlert
|
||||
- By using the service you agree to these terms
|
||||
- Governing law: England and Wales
|
||||
|
||||
**2. The service**
|
||||
- What FuelAlert does
|
||||
- Free tier and paid tier descriptions
|
||||
- We may add, remove, or change features with reasonable notice
|
||||
|
||||
**3. Your account**
|
||||
- Eligibility: 18+, UK resident, accurate information required
|
||||
- One account per person
|
||||
- You're responsible for keeping login credentials secure
|
||||
- We may suspend accounts for breach of these terms
|
||||
|
||||
**4. Subscriptions, billing and payment**
|
||||
This is the section Stripe cares most about. Cover:
|
||||
- Prices (link to /pricing) — currently £0.99/mo Daily, £2.49/mo Smart, with annual discount
|
||||
- Billing cycle: monthly or annual, charged in advance
|
||||
- **Auto-renewal**: subscriptions auto-renew at the end of each period at the then-current price, until cancelled
|
||||
- Payment method: card via Stripe; you authorise FuelAlert (via Stripe) to charge your method on each renewal
|
||||
- Failed payments: we'll retry and notify you; persistent failure suspends paid features
|
||||
- Price changes: 30 days' notice by email before any price increase takes effect on renewal; you may cancel before the increase
|
||||
- VAT: prices include UK VAT where applicable (sole traders below the VAT threshold do not charge VAT — clarify FuelAlert's current status)
|
||||
|
||||
**5. Cancellation and refunds**
|
||||
Cross-reference the Refund Policy. Summarise:
|
||||
- You can cancel at any time from your account settings
|
||||
- Cancellation stops the next renewal; you keep access until the end of the current billing period
|
||||
- 14-day right to cancel for new subscribers (see Refund Policy for the express-consent mechanism that affects this)
|
||||
|
||||
**6. Acceptable use**
|
||||
You agree not to:
|
||||
- Scrape, reverse-engineer, or bulk-extract data from the service
|
||||
- Resell or redistribute price data
|
||||
- Use the service for any unlawful purpose
|
||||
- Attempt to compromise security
|
||||
- Create automated queries beyond normal personal use
|
||||
|
||||
**7. Accuracy of price data — IMPORTANT**
|
||||
This is your liability shield. Say clearly:
|
||||
- Prices are sourced from official UK government data feeds (Pump Watch / Fuel Finder) and refreshed periodically
|
||||
- We make reasonable efforts to display accurate prices but **cannot guarantee** prices are correct at the moment you arrive at a station
|
||||
- Stations may change prices between data feed updates
|
||||
- FuelAlert is not liable for losses arising from inaccurate price data (wasted journey, fuel cost differences, etc.)
|
||||
- Always confirm the price at the pump before fuelling
|
||||
|
||||
**8. Forecasts and predictions**
|
||||
- Forecasts are informational only and not financial advice
|
||||
- Past trends do not guarantee future prices
|
||||
- We do not warrant the accuracy of any forecast
|
||||
|
||||
**9. Intellectual property**
|
||||
- The FuelAlert name, logo, software, and original content are owned by Ovidiu Ungureanu
|
||||
- Underlying fuel price data is owned by the respective retailers and published under government open data schemes; ONS Postcode Directory data is © Crown Copyright, used under Open Government Licence v3.0
|
||||
- You get a limited, non-exclusive, revocable licence to use the service for personal, non-commercial purposes (or commercial fleet use if on a Fleet plan)
|
||||
|
||||
**10. Third-party services**
|
||||
We use Stripe for payments. Your use of Stripe is also subject to Stripe's terms.
|
||||
|
||||
**11. Limitation of liability**
|
||||
- We don't exclude liability for death/personal injury caused by negligence, fraud, or anything that can't be excluded under UK consumer law
|
||||
- We exclude liability for indirect, consequential, or business losses
|
||||
- For consumers using the paid service, our total liability in any 12-month period is capped at the amount you paid in subscription fees in that period
|
||||
- We don't accept liability for issues caused by third-party services we depend on (Stripe outage, data feed outage, etc.)
|
||||
|
||||
**12. Termination**
|
||||
- You can stop using the service and close your account at any time
|
||||
- We can terminate access for serious breach of these terms, with notice where reasonable
|
||||
- On termination, paid sections 4–11 of these terms survive
|
||||
|
||||
**13. Changes to these terms**
|
||||
We may update these terms; material changes notified by email at least 14 days before they take effect.
|
||||
|
||||
**14. Disputes**
|
||||
- Try to resolve directly by contacting us first
|
||||
- These terms are governed by the laws of England and Wales; courts of England and Wales have non-exclusive jurisdiction
|
||||
- Consumers retain the right to bring proceedings in their country of residence
|
||||
- Reference to alternative dispute resolution if applicable
|
||||
|
||||
**15. Contact**
|
||||
Email address.
|
||||
|
||||
---
|
||||
|
||||
## 3. Refund & Cancellation Policy (`/legal/refund`)
|
||||
|
||||
This page is required by Stripe specifically and by UK consumer law. Keep it short and clear.
|
||||
|
||||
### Required sections:
|
||||
|
||||
**1. Your 14-day right to cancel (cooling-off period)**
|
||||
- Under the Consumer Contracts Regulations 2013, you have 14 days from the date you subscribe to cancel without giving a reason
|
||||
- This applies to **new subscribers only**; not subsequent renewals
|
||||
|
||||
**2. Express consent to start the service immediately — CRITICAL CLAUSE**
|
||||
- When you subscribe, you can choose to start using the paid features immediately
|
||||
- By doing so, you expressly acknowledge that you **lose your right to cancel** once the service has been fully supplied (i.e. once you've used the paid features within the 14-day window)
|
||||
- If you cancel before using the paid features, you receive a full refund
|
||||
- If you cancel within 14 days having used some paid features, we may reduce the refund proportionally to reflect usage
|
||||
|
||||
**Implementation note for the signup flow:** the express consent must be an unticked checkbox at checkout, with explicit text. Do not pre-tick it. Suggested wording for the checkbox label:
|
||||
> "I want my subscription to start immediately. I understand that by using paid features within the 14-day cooling-off period, I will lose my right to cancel under the Consumer Contracts Regulations 2013."
|
||||
|
||||
**3. How to cancel**
|
||||
- From your account: Settings → Subscription → Cancel
|
||||
- Or by emailing the contact address
|
||||
- Cancellation is effective at the end of the current billing period unless you exercise the 14-day right above
|
||||
|
||||
**4. Refunds outside the 14-day period**
|
||||
- After 14 days, subscription fees are non-refundable for the remainder of the period you paid for
|
||||
- You keep access until the end of the period
|
||||
- We may issue discretionary refunds in cases of service failure or where required by law
|
||||
|
||||
**5. Annual subscriptions**
|
||||
- Same 14-day right applies
|
||||
- After 14 days, annual fees are non-refundable; no pro-rata refund for unused months
|
||||
|
||||
**6. Failed payments and involuntary cancellation**
|
||||
- If your payment fails, we'll retry and notify you
|
||||
- Paid features suspend after [N] failed retries
|
||||
- Your account is not deleted; you can resume by updating payment
|
||||
|
||||
**7. How long refunds take**
|
||||
- Refunds are issued to the original payment method within 5–10 business days of approval
|
||||
|
||||
**8. Contact**
|
||||
Email address for refund requests.
|
||||
|
||||
---
|
||||
|
||||
## 4. Cookie Policy (`/legal/cookies`)
|
||||
|
||||
### Required sections:
|
||||
|
||||
**1. What cookies are**
|
||||
One short paragraph.
|
||||
|
||||
**2. Cookies we use**
|
||||
Table format with columns: Name | Purpose | Duration | Type (Essential / Analytics / Marketing).
|
||||
|
||||
Categories to include:
|
||||
- **Essential**: session, CSRF, authentication, cookie-consent preference itself — these do not require consent under PECR
|
||||
- **Analytics**: only if you use them; name them specifically (Plausible is cookie-less in many configs, GA4 uses several)
|
||||
- **Marketing**: only if you run any — likely none at launch
|
||||
|
||||
--- ignore for now. need to decide what tool to use for this
|
||||
|
||||
**3. Your choices**
|
||||
- You can accept, decline, or customise non-essential cookies via the consent banner
|
||||
- You can change your choice at any time via "Cookie Settings" in the footer
|
||||
- Most browsers also let you block cookies — link to ICO guidance on managing cookies
|
||||
|
||||
**4. Changes to this policy**
|
||||
Standard wording.
|
||||
|
||||
**5. Contact**
|
||||
Email.
|
||||
|
||||
---
|
||||
|
||||
## Cookie consent banner (separate component)
|
||||
|
||||
Implement as a Blade component, server-rendered, that:
|
||||
|
||||
- Appears on first visit
|
||||
- Has three buttons: **Accept all**, **Reject all**, **Customise**
|
||||
- "Customise" expands to checkboxes per category (Essential — locked on; Analytics; Marketing if applicable)
|
||||
- Stores choice in a first-party cookie (`fa_cookie_consent`) for 12 months
|
||||
- **Blocks non-essential scripts from loading until consent is given** — this is the critical bit. Use a tag manager pattern or conditional Blade includes; do NOT load Google Analytics, etc. before consent.
|
||||
- Persistent "Cookie Settings" link in the footer reopens the customise panel
|
||||
|
||||
PECR / ICO require equal prominence for accept and reject. Don't make "Reject" smaller or harder to find.
|
||||
|
||||
---
|
||||
|
||||
## Implementation notes for Claude Code
|
||||
|
||||
1. **Create Laravel routes** in `routes/web.php`:
|
||||
```php
|
||||
Route::view('/legal/privacy', 'legal.privacy')->name('legal.privacy');
|
||||
Route::view('/legal/terms', 'legal.terms')->name('legal.terms');
|
||||
Route::view('/legal/refund', 'legal.refund')->name('legal.refund');
|
||||
Route::view('/legal/cookies', 'legal.cookies')->name('legal.cookies');
|
||||
```
|
||||
|
||||
2. **Create Blade layout** `resources/views/layouts/legal.blade.php` extending the main site layout, with a narrow prose container.
|
||||
|
||||
3. **Each page** at `resources/views/legal/{name}.blade.php` should:
|
||||
- Set page title
|
||||
- Set meta description (short summary, ~150 chars)
|
||||
- Render the content in semantic HTML (h1, h2, h3, ul, ol, table where appropriate)
|
||||
- Show "Last updated: [date]" at top
|
||||
- Use Blade `@section` for content
|
||||
|
||||
4. **Update footer** to link to all four legal pages with `route()` helpers. Replace any existing "Cookie Settings" link with a button that opens the consent banner customise panel.
|
||||
|
||||
5. **Cookie banner component** at `resources/views/components/cookie-banner.blade.php` — include in main layout, with Alpine.js or vanilla JS for show/hide logic. Must be functional with JavaScript disabled (degrade to "you can change cookie settings in your browser" message).
|
||||
|
||||
6. **Do NOT** auto-generate the ICO registration number or contact email. Leave clear `[PLACEHOLDER: ...]` markers throughout for Ovidiu to fill in before deployment.
|
||||
|
||||
7. **Do NOT** include claims that aren't true yet — if uncertain, use a `[PLACEHOLDER: verify before launch]` marker rather than guessing.
|
||||
|
||||
8. **At the top of each generated file**, add a comment:
|
||||
```
|
||||
{{-- DRAFT: Generated [date]. Review by UK-qualified solicitor recommended before launch. --}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pre-launch checklist for Ovidiu (not for Claude Code)
|
||||
|
||||
- [ ] Register with the ICO (ico.org.uk) and obtain registration number — required by law for processing personal data commercially
|
||||
- [ ] Replace all `[PLACEHOLDER: ...]` markers
|
||||
- [ ] Confirm hosting provider and processors named in the Privacy Policy are accurate
|
||||
- [ ] Test the cookie banner: does it block non-essential scripts before consent?
|
||||
- [ ] Test the signup flow: is the express-consent checkbox unticked by default?
|
||||
- [ ] Test account cancellation: does it work end-to-end?
|
||||
- [ ] Have a UK-qualified solicitor review (or use Termly/iubenda as a sanity check)
|
||||
- [ ] Set `last_updated` dates to the actual go-live date
|
||||
- [ ] Submit to Stripe with the live URL
|
||||
@@ -402,9 +402,10 @@
|
||||
<div class="space-y-4">
|
||||
<h5 class="font-black text-xs text-zinc-800 tracking-widest">Legal</h5>
|
||||
<ul class="space-y-2 text-sm text-zinc-500">
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Privacy Policy</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Terms of Service</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="#">Cookie Settings</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/privacy">Privacy Policy</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/terms">Terms of Service</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/refund">Refund & Cancellation</a></li>
|
||||
<li><a class="hover:text-accent transition-colors" href="/legal/cookies">Cookie Policy</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
53
resources/views/components/layouts/legal.blade.php
Normal file
53
resources/views/components/layouts/legal.blade.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||
<head>
|
||||
@include('partials.head', ['title' => $title ?? null])
|
||||
@isset($metaDescription)
|
||||
<meta name="description" content="{{ $metaDescription }}">
|
||||
@endisset
|
||||
</head>
|
||||
<body class="min-h-screen bg-[#f5ede5] text-zinc-900 antialiased">
|
||||
<header class="border-b border-zinc-300 bg-white/70 backdrop-blur">
|
||||
<div class="mx-auto flex max-w-3xl items-center justify-between px-6 py-4">
|
||||
<a href="/" class="flex items-center gap-2">
|
||||
<span class="flex h-8 w-8 items-center justify-center rounded bg-accent text-white">
|
||||
<iconify-icon icon="lucide:fuel"></iconify-icon>
|
||||
</span>
|
||||
<span class="font-display text-xl font-black tracking-tighter text-accent">FuelAlert</span>
|
||||
</a>
|
||||
<a href="/" class="text-sm text-zinc-600 hover:text-accent">← Back to site</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="mx-auto max-w-3xl px-6 py-12">
|
||||
<article class="space-y-6 leading-relaxed text-zinc-800">
|
||||
<header class="space-y-3 border-b border-zinc-300 pb-6">
|
||||
<h1 class="font-display text-3xl font-black tracking-tight text-zinc-900 md:text-4xl">
|
||||
{{ $heading }}
|
||||
</h1>
|
||||
@isset($lastUpdated)
|
||||
<p class="text-sm text-zinc-500">Last updated: {{ $lastUpdated }}</p>
|
||||
@endisset
|
||||
</header>
|
||||
|
||||
{{ $slot }}
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<footer class="mt-16 border-t border-zinc-300 bg-white/50">
|
||||
<div class="mx-auto max-w-3xl px-6 py-10 text-sm text-zinc-600">
|
||||
<nav class="flex flex-wrap gap-x-6 gap-y-2">
|
||||
<a class="hover:text-accent" href="{{ route('legal.privacy') }}">Privacy Policy</a>
|
||||
<a class="hover:text-accent" href="{{ route('legal.terms') }}">Terms of Service</a>
|
||||
<a class="hover:text-accent" href="{{ route('legal.refund') }}">Refund & Cancellation</a>
|
||||
<a class="hover:text-accent" href="{{ route('legal.cookies') }}">Cookie Policy</a>
|
||||
</nav>
|
||||
<p class="mt-6 text-xs text-zinc-500">
|
||||
© {{ date('Y') }} FuelAlert. A trading name of Ovidiu Ungureanu, sole trader, Peterborough, United Kingdom.
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://code.iconify.design/iconify-icon/1.0.7/iconify-icon.min.js" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
112
resources/views/legal/cookies.blade.php
Normal file
112
resources/views/legal/cookies.blade.php
Normal file
@@ -0,0 +1,112 @@
|
||||
{{-- DRAFT: Generated {{ date('Y-m-d') }}. Review by UK-qualified solicitor recommended before launch. --}}
|
||||
<x-layouts.legal
|
||||
title="Cookie Policy"
|
||||
heading="Cookie Policy"
|
||||
lastUpdated="{{ now()->format('j F Y') }}"
|
||||
metaDescription="The cookies and similar technologies FuelAlert uses, and how to manage them.">
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">1. What cookies are</h2>
|
||||
<p>
|
||||
Cookies are small text files placed on your device by websites you visit. They allow a
|
||||
site to remember things between visits (for example, that you're signed in) and to
|
||||
measure how the site is used. This policy explains how FuelAlert uses cookies and
|
||||
similar technologies, and how you can manage them.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">2. Cookies we use</h2>
|
||||
<p>
|
||||
FuelAlert uses only <strong>essential</strong> cookies — cookies that are strictly
|
||||
necessary to deliver the service you've asked for. Under the Privacy and Electronic
|
||||
Communications Regulations (PECR), these do not require your consent, but we list them
|
||||
here for transparency.
|
||||
</p>
|
||||
<p>
|
||||
For aggregated usage metrics we run our own self-hosted instance of
|
||||
<strong>Umami Analytics</strong>, which is <strong>cookieless</strong> — it does
|
||||
not set any cookies, does not use device fingerprinting, and does not track you across
|
||||
sites. Because no personal data is collected, no consent is required.
|
||||
</p>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full border-collapse text-left text-sm">
|
||||
<thead class="bg-zinc-100">
|
||||
<tr>
|
||||
<th class="border border-zinc-300 px-3 py-2 font-semibold">Name</th>
|
||||
<th class="border border-zinc-300 px-3 py-2 font-semibold">Purpose</th>
|
||||
<th class="border border-zinc-300 px-3 py-2 font-semibold">Duration</th>
|
||||
<th class="border border-zinc-300 px-3 py-2 font-semibold">Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="border border-zinc-300 px-3 py-2 font-mono text-xs">fuel_alert_session</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Keeps you signed in and maintains your session state.</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Session</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Essential</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-zinc-300 px-3 py-2 font-mono text-xs">XSRF-TOKEN</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Protects against cross-site request forgery attacks on forms and account actions.</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Session</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Essential</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-zinc-300 px-3 py-2 font-mono text-xs">remember_web_*</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">"Remember me" — keeps you signed in across browser restarts if you tick the box at login.</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Up to 5 years</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Essential</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="border border-zinc-300 px-3 py-2 font-mono text-xs">fa_location</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Stores your most recent postcode search so we can show local prices on return visits without re-querying.</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">30 days</td>
|
||||
<td class="border border-zinc-300 px-3 py-2">Essential</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-zinc-600">
|
||||
<strong>[PLACEHOLDER:</strong> Update the table above if any cookie names change. If a
|
||||
marketing tool is added in future, a Marketing row will be added here and consent will
|
||||
be requested before it loads.<strong>]</strong>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">3. Your choices</h2>
|
||||
<p>
|
||||
Because we currently only use essential cookies, there is nothing to opt in or out of
|
||||
on FuelAlert at this time. If we add non-essential cookies in future (for example,
|
||||
analytics or marketing), we will present a consent banner and you will be able to
|
||||
accept, reject, or customise your choice. We will not set non-essential cookies before
|
||||
you have given consent.
|
||||
</p>
|
||||
<p>
|
||||
All major browsers also let you view, block, or delete cookies. The ICO publishes
|
||||
guidance on managing cookies in your browser:
|
||||
<a class="text-accent underline" href="https://ico.org.uk/your-data-matters/online/cookies/" target="_blank" rel="noopener">ico.org.uk · managing cookies</a>.
|
||||
Note that blocking essential cookies will prevent you from signing in.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">4. Changes to this policy</h2>
|
||||
<p>
|
||||
We may update this policy if we add new cookies, change our providers, or in response to
|
||||
legal or guidance changes. Material changes will be highlighted by an updated
|
||||
"Last updated" date at the top of this page.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">5. Contact</h2>
|
||||
<p>
|
||||
Questions about cookies? Email
|
||||
<a href="mailto:[PLACEHOLDER: hello@fuelalert.co.uk]" class="text-accent underline">[PLACEHOLDER: hello@fuelalert.co.uk]</a>.
|
||||
</p>
|
||||
</section>
|
||||
</x-layouts.legal>
|
||||
205
resources/views/legal/privacy.blade.php
Normal file
205
resources/views/legal/privacy.blade.php
Normal file
@@ -0,0 +1,205 @@
|
||||
{{-- DRAFT: Generated {{ date('Y-m-d') }}. Review by UK-qualified solicitor recommended before launch. --}}
|
||||
<x-layouts.legal
|
||||
title="Privacy Policy"
|
||||
heading="Privacy Policy"
|
||||
lastUpdated="{{ now()->format('j F Y') }}"
|
||||
metaDescription="How FuelAlert collects, uses and protects your personal data under UK GDPR.">
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">1. Who we are</h2>
|
||||
<p>
|
||||
FuelAlert is a trading name of <strong>Ovidiu Ungureanu</strong>, a sole trader based in
|
||||
Peterborough, United Kingdom. For the purposes of UK data protection law, Ovidiu Ungureanu
|
||||
is the <strong>data controller</strong> for personal data collected through this service.
|
||||
</p>
|
||||
<p>
|
||||
We are registered with the UK Information Commissioner's Office (ICO).
|
||||
Our registration number is <strong>[PLACEHOLDER: ICO registration number ZAxxxxxxx]</strong>.
|
||||
</p>
|
||||
<p>
|
||||
If you have any questions about this policy or how we handle your personal data, contact us at
|
||||
<a href="mailto:[PLACEHOLDER: hello@fuelalert.co.uk]" class="text-accent underline">[PLACEHOLDER: hello@fuelalert.co.uk]</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">2. What data we collect</h2>
|
||||
|
||||
<h3 class="font-semibold text-zinc-900">Account data</h3>
|
||||
<p>Your email address, a hashed password, and the date you created your account.</p>
|
||||
|
||||
<h3 class="font-semibold text-zinc-900">Location data</h3>
|
||||
<p>
|
||||
Postcodes or place names you search for. With your permission, your device's precise
|
||||
location to find nearby stations. Derived approximate location used to query our database.
|
||||
</p>
|
||||
|
||||
<h3 class="font-semibold text-zinc-900">Payment data</h3>
|
||||
<p>
|
||||
Payment card details are collected and processed by <strong>Stripe</strong>, our payment
|
||||
processor. FuelAlert does not see, store, or otherwise have access to your card numbers.
|
||||
We retain only your Stripe customer ID and subscription metadata (plan, billing cycle,
|
||||
renewal date).
|
||||
</p>
|
||||
|
||||
<h3 class="font-semibold text-zinc-900">Usage data</h3>
|
||||
<p>
|
||||
Features you use, queries you make, and alerts you configure — used to deliver the
|
||||
service and improve it.
|
||||
</p>
|
||||
|
||||
<h3 class="font-semibold text-zinc-900">Technical data</h3>
|
||||
<p>
|
||||
IP address, browser type and version, device type, and operating system — used for
|
||||
security, fraud prevention, and basic analytics.
|
||||
</p>
|
||||
|
||||
<h3 class="font-semibold text-zinc-900">Marketing preferences</h3>
|
||||
<p>Only collected if you opt in to marketing communications.</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">3. Lawful basis for processing</h2>
|
||||
<p>We process your personal data under the following bases of UK GDPR Article 6:</p>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li><strong>Account creation and service delivery</strong> — contract (Art. 6(1)(b)).</li>
|
||||
<li><strong>Payment processing</strong> — contract (Art. 6(1)(b)).</li>
|
||||
<li><strong>Security and fraud prevention</strong> — legitimate interests (Art. 6(1)(f)).</li>
|
||||
<li><strong>Analytics and product improvement</strong> — legitimate interests, with opt-out via our cookie banner where applicable.</li>
|
||||
<li><strong>Marketing emails</strong> — consent (Art. 6(1)(a)). You can withdraw consent at any time.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">4. How we use your data</h2>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li>To create and operate your account (contract).</li>
|
||||
<li>To deliver fuel price information and alerts you have configured (contract).</li>
|
||||
<li>To process subscription payments via Stripe (contract).</li>
|
||||
<li>To keep our service secure and prevent abuse (legitimate interests).</li>
|
||||
<li>To understand which features are used and improve the product (legitimate interests).</li>
|
||||
<li>To respond to your support enquiries (contract / legitimate interests).</li>
|
||||
<li>To send marketing emails if you have opted in (consent).</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">5. Who we share data with</h2>
|
||||
<p>We use the following processors to deliver the service. We do not sell your data to anyone.</p>
|
||||
<ul class="list-disc space-y-2 pl-6">
|
||||
<li>
|
||||
<strong>Stripe</strong> — payment processing. Card details, billing address,
|
||||
and subscription events flow to Stripe. See
|
||||
<a class="text-accent underline" href="https://stripe.com/privacy" target="_blank" rel="noopener">Stripe's privacy policy</a>.
|
||||
</li>
|
||||
<li><strong>[PLACEHOLDER: Hosting provider]</strong> — infrastructure where our application and database run.</li>
|
||||
<li><strong>[PLACEHOLDER: Transactional email provider]</strong> — sends account, billing and alert emails on our behalf.</li>
|
||||
<li>
|
||||
<strong>Umami Analytics</strong> — we run our own self-hosted Umami instance to
|
||||
collect aggregated, cookieless usage metrics (pages viewed, referrer, country, device
|
||||
type). No personal data is collected and no analytics data is shared with third
|
||||
parties.
|
||||
</li>
|
||||
<li><strong>[PLACEHOLDER: Notification providers]</strong> — if you opt in to push, WhatsApp, or SMS alerts, the chosen provider will be named here.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">6. International transfers</h2>
|
||||
<p>
|
||||
Some of our processors (notably Stripe) operate outside the UK and EEA, including in the
|
||||
United States. Where personal data is transferred internationally, we rely on appropriate
|
||||
safeguards under UK GDPR: the UK International Data Transfer Addendum to the EU Standard
|
||||
Contractual Clauses, or an equivalent mechanism.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">7. How long we keep data</h2>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li><strong>Active account data:</strong> for as long as your account is open, plus 12 months after closure.</li>
|
||||
<li><strong>Payment records:</strong> 6 years, to meet HMRC requirements for self-employed traders.</li>
|
||||
<li><strong>Marketing data:</strong> until you withdraw consent.</li>
|
||||
<li><strong>Logs and analytics:</strong> a maximum of 24 months.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">8. Your rights under UK GDPR</h2>
|
||||
<p>You have the following rights in relation to your personal data:</p>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li><strong>Right of access</strong> — ask for a copy of the data we hold about you.</li>
|
||||
<li><strong>Right to rectification</strong> — ask us to correct inaccurate data.</li>
|
||||
<li><strong>Right to erasure</strong> ("right to be forgotten") — ask us to delete your data.</li>
|
||||
<li><strong>Right to restrict processing</strong> — ask us to pause processing in certain circumstances.</li>
|
||||
<li><strong>Right to data portability</strong> — receive your data in a machine-readable format.</li>
|
||||
<li><strong>Right to object</strong> — object to processing based on legitimate interests.</li>
|
||||
<li><strong>Rights related to automated decision-making</strong> — we do <strong>not</strong> make solely automated decisions with legal or similarly significant effects on you.</li>
|
||||
<li><strong>Right to withdraw consent</strong> — where we rely on consent (e.g. marketing).</li>
|
||||
</ul>
|
||||
<p>
|
||||
To exercise any of these rights, email
|
||||
<a href="mailto:[PLACEHOLDER: hello@fuelalert.co.uk]" class="text-accent underline">[PLACEHOLDER: hello@fuelalert.co.uk]</a>.
|
||||
We will respond within one month.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">9. Cookies</h2>
|
||||
<p>
|
||||
We use a small number of cookies to operate the service. Full details — including
|
||||
categories and how to change your choices — are in our
|
||||
<a class="text-accent underline" href="{{ route('legal.cookies') }}">Cookie Policy</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">10. Security</h2>
|
||||
<p>
|
||||
All traffic between your device and our service is encrypted with HTTPS. Passwords are
|
||||
stored as one-way hashes — we never see your plaintext password. Sensitive fields in
|
||||
our database are protected by access controls, and our infrastructure receives regular
|
||||
security updates. No system is ever 100% secure; if a breach occurs that affects you, we
|
||||
will notify you and the ICO as required by law.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">11. Children</h2>
|
||||
<p>
|
||||
FuelAlert is not directed at children. We do not knowingly collect data from anyone under
|
||||
16. If you believe a child has provided us with personal data, contact us and we will
|
||||
delete it.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">12. Complaints</h2>
|
||||
<p>
|
||||
We hope you'll contact us first if you have a complaint, so we can try to put it right.
|
||||
You also have the right to lodge a complaint with the UK Information Commissioner's Office
|
||||
at any time.
|
||||
</p>
|
||||
<p>
|
||||
ICO website: <a class="text-accent underline" href="https://ico.org.uk" target="_blank" rel="noopener">ico.org.uk</a>
|
||||
· ICO helpline: 0303 123 1113.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">13. Changes to this policy</h2>
|
||||
<p>
|
||||
We may update this policy from time to time. If we make material changes we will notify
|
||||
registered users by email. Non-material changes will be shown by an updated "Last updated"
|
||||
date at the top of this page.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">14. Contact</h2>
|
||||
<p>
|
||||
For any privacy queries, email
|
||||
<a href="mailto:[PLACEHOLDER: hello@fuelalert.co.uk]" class="text-accent underline">[PLACEHOLDER: hello@fuelalert.co.uk]</a>.
|
||||
</p>
|
||||
</section>
|
||||
</x-layouts.legal>
|
||||
110
resources/views/legal/refund.blade.php
Normal file
110
resources/views/legal/refund.blade.php
Normal file
@@ -0,0 +1,110 @@
|
||||
{{-- DRAFT: Generated {{ date('Y-m-d') }}. Review by UK-qualified solicitor recommended before launch. --}}
|
||||
<x-layouts.legal
|
||||
title="Refund & Cancellation Policy"
|
||||
heading="Refund & Cancellation Policy"
|
||||
lastUpdated="{{ now()->format('j F Y') }}"
|
||||
metaDescription="Your right to cancel a FuelAlert subscription, including the 14-day cooling-off period under UK law.">
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">1. Your 14-day right to cancel</h2>
|
||||
<p>
|
||||
Under the <strong>Consumer Contracts (Information, Cancellation and Additional Charges)
|
||||
Regulations 2013</strong>, you have <strong>14 days</strong> from the date you subscribe
|
||||
to a paid plan to cancel without giving a reason. This is sometimes called the
|
||||
"cooling-off period".
|
||||
</p>
|
||||
<p>
|
||||
This 14-day right applies to <strong>new subscribers only</strong>. It does not apply to
|
||||
subsequent automatic renewals of an existing subscription.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3 rounded-lg border-l-4 border-accent bg-white/70 p-6">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">2. Express consent to start the service immediately</h2>
|
||||
<p>
|
||||
When you subscribe, we ask you to choose whether the paid features should be available
|
||||
to you immediately. If you tick the consent box and start using paid features within the
|
||||
14-day window, you expressly acknowledge that:
|
||||
</p>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li>The service is being supplied to you straight away;</li>
|
||||
<li>
|
||||
<strong>You will lose your right to cancel under the Consumer Contracts Regulations
|
||||
2013 once the service has been fully supplied</strong> (i.e. once you have used the
|
||||
paid features during the cooling-off period).
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
If you do <strong>not</strong> tick the express-consent box, your subscription is still
|
||||
created but paid features remain inactive until the cooling-off period ends, or until
|
||||
you change your mind and confirm consent.
|
||||
</p>
|
||||
<p>
|
||||
If you cancel within the 14-day window <strong>before</strong> using any paid features,
|
||||
you receive a <strong>full refund</strong>. If you cancel within the window after using
|
||||
some paid features, we may reduce the refund proportionally to reflect usage, as
|
||||
permitted by the Regulations.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">3. How to cancel</h2>
|
||||
<p>You can cancel a subscription in either of these ways:</p>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li>From your account: <strong>Settings → Subscription → Cancel</strong>.</li>
|
||||
<li>By emailing <a href="mailto:[PLACEHOLDER: hello@fuelalert.co.uk]" class="text-accent underline">[PLACEHOLDER: hello@fuelalert.co.uk]</a> from the address on your account.</li>
|
||||
</ul>
|
||||
<p>
|
||||
Unless you are exercising the 14-day right above, cancellation takes effect at the end
|
||||
of the current billing period. You keep access to paid features until that date.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">4. Refunds outside the 14-day period</h2>
|
||||
<p>
|
||||
Outside the 14-day cooling-off window, subscription fees are <strong>non-refundable</strong>
|
||||
for the remainder of the period you have paid for. You keep access to paid features
|
||||
until the end of that period; the subscription simply does not renew.
|
||||
</p>
|
||||
<p>
|
||||
We may issue discretionary refunds where there has been a service failure on our side or
|
||||
where required by law.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">5. Annual subscriptions</h2>
|
||||
<p>
|
||||
The 14-day cooling-off right applies to annual subscriptions in the same way as monthly
|
||||
subscriptions. After the 14 days, annual fees are non-refundable; we do not issue
|
||||
pro-rata refunds for unused months of an annual plan.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">6. Failed payments and involuntary cancellation</h2>
|
||||
<p>
|
||||
If a renewal payment fails, we and Stripe will retry the payment over a short period and
|
||||
email you. Paid features are suspended after the final unsuccessful retry. Your account
|
||||
itself is <strong>not deleted</strong>; you can resume by updating your payment method.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">7. How long refunds take</h2>
|
||||
<p>
|
||||
Approved refunds are issued to the original payment method via Stripe and typically
|
||||
arrive in your account within 5–10 business days, depending on your bank or card
|
||||
provider.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">8. Contact</h2>
|
||||
<p>
|
||||
For refund or cancellation queries, email
|
||||
<a href="mailto:[PLACEHOLDER: hello@fuelalert.co.uk]" class="text-accent underline">[PLACEHOLDER: hello@fuelalert.co.uk]</a>.
|
||||
</p>
|
||||
</section>
|
||||
</x-layouts.legal>
|
||||
221
resources/views/legal/terms.blade.php
Normal file
221
resources/views/legal/terms.blade.php
Normal file
@@ -0,0 +1,221 @@
|
||||
{{-- DRAFT: Generated {{ date('Y-m-d') }}. Review by UK-qualified solicitor recommended before launch. --}}
|
||||
<x-layouts.legal
|
||||
title="Terms of Service"
|
||||
heading="Terms of Service"
|
||||
lastUpdated="{{ now()->format('j F Y') }}"
|
||||
metaDescription="The terms that govern your use of FuelAlert's subscription service.">
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">1. About these terms</h2>
|
||||
<p>
|
||||
FuelAlert is a trading name of <strong>Ovidiu Ungureanu</strong>, a sole trader based in
|
||||
Peterborough, United Kingdom ("we", "us", "our"). These terms form a legally binding
|
||||
contract between you and Ovidiu Ungureanu trading as FuelAlert.
|
||||
</p>
|
||||
<p>
|
||||
By creating an account or using the service, you confirm that you have read, understood
|
||||
and accepted these terms. If you do not accept them, please do not use the service.
|
||||
</p>
|
||||
<p>These terms are governed by the laws of England and Wales.</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">2. The service</h2>
|
||||
<p>
|
||||
FuelAlert provides UK fuel price comparison and forecasting. We aggregate publicly
|
||||
available UK fuel price data and surface it through a web app, alerts and forecasts.
|
||||
</p>
|
||||
<p>
|
||||
We offer a free tier and one or more paid subscription plans. The current list of plans
|
||||
and prices is available on our <a class="text-accent underline" href="/#pricing">pricing page</a>.
|
||||
</p>
|
||||
<p>
|
||||
We may add, remove, or change features over time. Where changes materially reduce the
|
||||
paid service, we will give you reasonable notice and, where appropriate, a way to cancel.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">3. Your account</h2>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li>You must be at least 18 years old and resident in the United Kingdom to create an account.</li>
|
||||
<li>The information you provide must be accurate and kept up to date.</li>
|
||||
<li>One account per person. You are responsible for keeping your login credentials secure.</li>
|
||||
<li>You are responsible for activity that takes place under your account.</li>
|
||||
<li>We may suspend or close accounts where these terms are seriously or repeatedly breached.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">4. Subscriptions, billing and payment</h2>
|
||||
<p>
|
||||
Paid plans are billed in advance, either monthly or annually. The current price for each
|
||||
plan is shown on the <a class="text-accent underline" href="/#pricing">pricing page</a> at the time you subscribe.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Auto-renewal.</strong> Subscriptions renew automatically at the end of each
|
||||
billing period at the then-current price, unless you cancel before the renewal date. By
|
||||
subscribing you authorise FuelAlert — through our payment processor Stripe —
|
||||
to charge your nominated payment method at each renewal.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Failed payments.</strong> If a payment fails, we and Stripe will retry the
|
||||
payment over the following days. We will email you when this happens. Persistent failure
|
||||
will cause your paid features to be suspended; your account itself is not deleted.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Price changes.</strong> If we change the price of your plan, we will give you at
|
||||
least 30 days' notice by email before the new price takes effect on your next renewal.
|
||||
You may cancel before the change takes effect.
|
||||
</p>
|
||||
<p>
|
||||
<strong>VAT.</strong> Prices include UK VAT where applicable.
|
||||
<strong>[PLACEHOLDER: verify before launch — FuelAlert is currently below the UK VAT registration threshold and therefore does not charge VAT.]</strong>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">5. Cancellation and refunds</h2>
|
||||
<p>
|
||||
You can cancel your subscription at any time from your account settings. Cancellation
|
||||
stops the next renewal; you keep access to paid features until the end of the current
|
||||
billing period.
|
||||
</p>
|
||||
<p>
|
||||
New subscribers have a <strong>14-day right to cancel</strong> under the Consumer
|
||||
Contracts Regulations 2013. Important details — including the express-consent
|
||||
mechanism that affects this right — are set out in our
|
||||
<a class="text-accent underline" href="{{ route('legal.refund') }}">Refund & Cancellation Policy</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">6. Acceptable use</h2>
|
||||
<p>You agree not to:</p>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li>Scrape, reverse-engineer, or bulk-extract data from the service.</li>
|
||||
<li>Resell or redistribute fuel price data taken from FuelAlert.</li>
|
||||
<li>Use the service for any unlawful purpose.</li>
|
||||
<li>Attempt to circumvent or compromise our security measures.</li>
|
||||
<li>Use automated tools to make queries beyond what a single human user would reasonably make.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">7. Accuracy of price data</h2>
|
||||
<p>
|
||||
Fuel prices shown on FuelAlert are sourced from official UK government data feeds
|
||||
(including the Pump Watch / Fuel Finder transparency schemes) and refreshed
|
||||
periodically. Stations can change prices at any time, and there is usually a delay
|
||||
between a forecourt change and the feed update.
|
||||
</p>
|
||||
<p>
|
||||
We make reasonable efforts to display accurate prices but <strong>we cannot guarantee
|
||||
that the price shown will match the price at the pump</strong> when you arrive.
|
||||
<strong>Always confirm the price at the pump before fuelling.</strong>
|
||||
</p>
|
||||
<p>
|
||||
We are not liable for any loss arising from inaccurate, delayed, or missing price data,
|
||||
including the cost of a wasted journey or any difference between the price shown and the
|
||||
price charged.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">8. Forecasts and predictions</h2>
|
||||
<p>
|
||||
FuelAlert may show forecasts and recommendations (e.g. "fill up now" or "wait"). These
|
||||
are <strong>informational only</strong>, are not financial advice, and should not be
|
||||
relied upon as a guarantee of future prices. Past trends do not guarantee future prices.
|
||||
We do not warrant the accuracy of any forecast.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">9. Intellectual property</h2>
|
||||
<p>
|
||||
The FuelAlert name, logo, software, and original content are owned by Ovidiu Ungureanu.
|
||||
You receive a limited, non-exclusive, revocable licence to use the service for personal,
|
||||
non-commercial purposes.
|
||||
</p>
|
||||
<p>
|
||||
Underlying fuel price data is owned by the respective fuel retailers and published under
|
||||
UK government open data schemes. Postcode and geographic data is sourced from the ONS
|
||||
Postcode Directory, © Crown Copyright, used under the Open Government Licence v3.0.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">10. Third-party services</h2>
|
||||
<p>
|
||||
We use <strong>Stripe</strong> to process payments. Your use of Stripe is also subject
|
||||
to Stripe's own terms and privacy policy. We may use other third-party processors to
|
||||
run the service; these are named in our
|
||||
<a class="text-accent underline" href="{{ route('legal.privacy') }}">Privacy Policy</a>.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">11. Limitation of liability</h2>
|
||||
<p>
|
||||
Nothing in these terms excludes or limits our liability for death or personal injury
|
||||
caused by our negligence, fraud or fraudulent misrepresentation, or any other liability
|
||||
that cannot be excluded under UK consumer law. Your statutory rights as a consumer are
|
||||
not affected.
|
||||
</p>
|
||||
<p>Subject to the paragraph above:</p>
|
||||
<ul class="list-disc space-y-1 pl-6">
|
||||
<li>We exclude liability for indirect, consequential, or business losses.</li>
|
||||
<li>
|
||||
For paying subscribers, our total liability to you in any 12-month period is capped
|
||||
at the total amount you paid in subscription fees during that period.
|
||||
</li>
|
||||
<li>
|
||||
We do not accept liability for issues caused by third-party services we rely on,
|
||||
including but not limited to outages or errors at our payment processor, hosting
|
||||
provider, or upstream data sources.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">12. Termination</h2>
|
||||
<p>
|
||||
You may stop using the service and close your account at any time. We may terminate or
|
||||
suspend access for serious breach of these terms, with reasonable notice where the
|
||||
breach is capable of being put right.
|
||||
</p>
|
||||
<p>
|
||||
Sections that by their nature should survive termination (including sections 7 to 11)
|
||||
will continue to apply after your account is closed.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">13. Changes to these terms</h2>
|
||||
<p>
|
||||
We may update these terms. Material changes will be notified to registered users by
|
||||
email at least 14 days before they take effect. Continued use of the service after the
|
||||
change date means you accept the new terms.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">14. Disputes</h2>
|
||||
<p>
|
||||
Please contact us first if you have a complaint — we will try to resolve it
|
||||
directly. These terms are governed by the laws of England and Wales, and the courts of
|
||||
England and Wales have non-exclusive jurisdiction over any dispute. If you live
|
||||
elsewhere in the United Kingdom, you keep the right to bring proceedings in the courts
|
||||
of your country of residence.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section class="space-y-3">
|
||||
<h2 class="font-display text-2xl font-bold text-zinc-900">15. Contact</h2>
|
||||
<p>
|
||||
For questions about these terms, email
|
||||
<a href="mailto:[PLACEHOLDER: hello@fuelalert.co.uk]" class="text-accent underline">[PLACEHOLDER: hello@fuelalert.co.uk]</a>.
|
||||
</p>
|
||||
</section>
|
||||
</x-layouts.legal>
|
||||
@@ -24,5 +24,13 @@ Route::middleware(['auth'])->prefix('billing')->name('billing.')->group(function
|
||||
Route::get('/cancel', [BillingController::class, 'cancel'])->name('cancel');
|
||||
});
|
||||
|
||||
// Server-rendered legal pages — must be registered before the SPA catch-all
|
||||
Route::prefix('legal')->name('legal.')->group(function () {
|
||||
Route::view('/privacy', 'legal.privacy')->name('privacy');
|
||||
Route::view('/terms', 'legal.terms')->name('terms');
|
||||
Route::view('/refund', 'legal.refund')->name('refund');
|
||||
Route::view('/cookies', 'legal.cookies')->name('cookies');
|
||||
});
|
||||
|
||||
// SPA catch-all — must be last
|
||||
Route::get('/{any?}', fn () => view('app'))->where('any', '.*')->name('home');
|
||||
|
||||
54
tests/Feature/LegalPagesTest.php
Normal file
54
tests/Feature/LegalPagesTest.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
it('serves the privacy policy with required content', function (): void {
|
||||
$response = $this->get('/legal/privacy');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertSeeText('Privacy Policy');
|
||||
$response->assertSeeText('data controller');
|
||||
$response->assertSeeText('UK GDPR');
|
||||
$response->assertSeeText('Last updated:');
|
||||
});
|
||||
|
||||
it('serves the terms of service with required content', function (): void {
|
||||
$response = $this->get('/legal/terms');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertSeeText('Terms of Service');
|
||||
$response->assertSeeText('subscription');
|
||||
$response->assertSeeText('England and Wales');
|
||||
});
|
||||
|
||||
it('serves the refund policy with cooling-off content', function (): void {
|
||||
$response = $this->get('/legal/refund');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertSeeText('Refund');
|
||||
$response->assertSeeText('14-day');
|
||||
$response->assertSeeText('Consumer Contracts');
|
||||
});
|
||||
|
||||
it('serves the cookie policy with essential-cookie content', function (): void {
|
||||
$response = $this->get('/legal/cookies');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertSeeText('Cookie Policy');
|
||||
$response->assertSeeText('essential');
|
||||
});
|
||||
|
||||
it('does not render the SPA mount point on legal pages', function (string $path): void {
|
||||
$response = $this->get($path);
|
||||
|
||||
$response->assertStatus(200);
|
||||
$response->assertDontSee('<div id="app"></div>', false);
|
||||
})->with([
|
||||
'/legal/privacy',
|
||||
'/legal/terms',
|
||||
'/legal/refund',
|
||||
'/legal/cookies',
|
||||
]);
|
||||
|
||||
it('cross-links between legal pages', function (): void {
|
||||
$this->get('/legal/privacy')->assertSee(route('legal.cookies'), false);
|
||||
$this->get('/legal/terms')->assertSee(route('legal.refund'), false);
|
||||
});
|
||||
Reference in New Issue
Block a user