feat: storefront subscription access guard + module-driven nav + URL rename

Add StorefrontAccessMiddleware that blocks storefront access for stores
without an active subscription, returning a multilingual unavailable page
(en/fr/de/lb) for page requests and JSON 403 for API requests. Multi-platform
aware: resolves subscription for detected platform with fallback to primary.

Also includes yesterday's session work:
- Module-driven storefront navigation via FrontendType.STOREFRONT menu declarations
- shop/ → storefront/ URL rename across 30+ templates
- Subscription context (tier_code) passed to storefront templates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-18 13:27:31 +01:00
parent 682213fdee
commit 2c710ad416
46 changed files with 1484 additions and 231 deletions

View File

@@ -172,7 +172,7 @@
</template>
<!-- Preview button -->
<a
:href="`/stores/${storeCode}/shop/${page.slug}`"
:href="`/stores/${storeCode}/storefront/${page.slug}`"
target="_blank"
class="flex items-center justify-center p-2 text-gray-500 rounded-lg hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700 transition-colors"
title="Preview"
@@ -278,7 +278,7 @@
<span x-html="$icon('edit', 'w-5 h-5')"></span>
</a>
<a
:href="`/stores/${storeCode}/shop/${page.slug}`"
:href="`/stores/${storeCode}/storefront/${page.slug}`"
target="_blank"
class="flex items-center justify-center p-2 text-gray-500 rounded-lg hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700 transition-colors"
title="Preview"

View File

@@ -1,7 +1,7 @@
{# app/templates/store/landing-default.html #}
{# standalone #}
{# Default/Minimal Landing Page Template #}
{% extends "shop/base.html" %}
{% extends "storefront/base.html" %}
{% block title %}{{ store.name }}{% endblock %}
{% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %}
@@ -36,7 +36,7 @@
{# CTA Button #}
<div class="flex flex-col sm:flex-row gap-4 justify-center">
<a href="{{ base_url }}shop/"
<a href="{{ base_url }}storefront/"
class="inline-flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-lg text-white bg-primary hover:bg-primary-dark transition-colors shadow-lg hover:shadow-xl"
style="background-color: var(--color-primary)">
Browse Our Shop
@@ -71,7 +71,7 @@
Explore
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<a href="{{ base_url }}shop/products"
<a href="{{ base_url }}storefront/products"
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
<div class="text-4xl mb-4">🛍️</div>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">
@@ -84,7 +84,7 @@
{% if header_pages %}
{% for page in header_pages[:2] %}
<a href="{{ base_url }}shop/{{ page.slug }}"
<a href="{{ base_url }}storefront/{{ page.slug }}"
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
<div class="text-4xl mb-4">📄</div>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">
@@ -96,7 +96,7 @@
</a>
{% endfor %}
{% else %}
<a href="{{ base_url }}shop/about"
<a href="{{ base_url }}storefront/about"
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
<div class="text-4xl mb-4"></div>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">
@@ -107,7 +107,7 @@
</p>
</a>
<a href="{{ base_url }}shop/contact"
<a href="{{ base_url }}storefront/contact"
class="block p-8 bg-white dark:bg-gray-900 rounded-lg shadow-md hover:shadow-xl transition-shadow text-center group">
<div class="text-4xl mb-4">📧</div>
<h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-2 group-hover:text-primary">

View File

@@ -1,7 +1,7 @@
{# app/templates/store/landing-full.html #}
{# standalone #}
{# Full Landing Page Template - Maximum Features #}
{% extends "shop/base.html" %}
{% extends "storefront/base.html" %}
{% block title %}{{ store.name }}{% endblock %}
{% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %}
@@ -43,7 +43,7 @@
{% endif %}
<div class="flex flex-col sm:flex-row gap-4">
<a href="{{ base_url }}shop/"
<a href="{{ base_url }}storefront/"
class="inline-flex items-center justify-center px-8 py-4 text-lg font-semibold rounded-lg text-white bg-primary hover:bg-primary-dark transition-colors shadow-lg"
style="background-color: var(--color-primary)">
Shop Now
@@ -174,7 +174,7 @@
Explore More
</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-8">
<a href="{{ base_url }}shop/products"
<a href="{{ base_url }}storefront/products"
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-primary/10 to-primary/5 dark:from-primary/20 dark:to-primary/10 p-8 hover:shadow-xl transition-all">
<div class="relative z-10">
<div class="text-5xl mb-4">🛍️</div>
@@ -190,7 +190,7 @@
{% if header_pages %}
{% for page in header_pages[:2] %}
<a href="{{ base_url }}shop/{{ page.slug }}"
<a href="{{ base_url }}storefront/{{ page.slug }}"
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-accent/10 to-accent/5 dark:from-accent/20 dark:to-accent/10 p-8 hover:shadow-xl transition-all">
<div class="relative z-10">
<div class="text-5xl mb-4">📄</div>
@@ -205,7 +205,7 @@
</a>
{% endfor %}
{% else %}
<a href="{{ base_url }}shop/about"
<a href="{{ base_url }}storefront/about"
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-accent/10 to-accent/5 dark:from-accent/20 dark:to-accent/10 p-8 hover:shadow-xl transition-all">
<div class="relative z-10">
<div class="text-5xl mb-4"></div>
@@ -219,7 +219,7 @@
<div class="absolute inset-0 bg-accent opacity-0 group-hover:opacity-5 transition-opacity"></div>
</a>
<a href="{{ base_url }}shop/contact"
<a href="{{ base_url }}storefront/contact"
class="group relative overflow-hidden rounded-2xl bg-gradient-to-br from-primary/10 to-primary/5 dark:from-primary/20 dark:to-primary/10 p-8 hover:shadow-xl transition-all">
<div class="relative z-10">
<div class="text-5xl mb-4">📧</div>
@@ -246,7 +246,7 @@
<p class="text-xl mb-10 opacity-90">
Join thousands of satisfied customers today
</p>
<a href="{{ base_url }}shop/products"
<a href="{{ base_url }}storefront/products"
class="inline-flex items-center justify-center px-10 py-5 text-lg font-bold rounded-xl text-primary bg-white hover:bg-gray-50 transition-all transform hover:scale-105 shadow-2xl">
View All Products
<span class="w-5 h-5 ml-2" x-html="$icon('arrow-right', 'w-5 h-5')"></span>

View File

@@ -1,7 +1,7 @@
{# app/templates/store/landing-minimal.html #}
{# standalone #}
{# Minimal Landing Page Template - Ultra Clean #}
{% extends "shop/base.html" %}
{% extends "storefront/base.html" %}
{% block title %}{{ store.name }}{% endblock %}
{% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %}
@@ -37,7 +37,7 @@
{# Single CTA #}
<div>
<a href="{{ base_url }}shop/"
<a href="{{ base_url }}storefront/"
class="inline-flex items-center justify-center px-10 py-5 text-xl font-semibold rounded-full text-white bg-primary hover:bg-primary-dark transition-all transform hover:scale-105 shadow-2xl"
style="background-color: var(--color-primary)">
Enter Shop
@@ -49,11 +49,11 @@
{% if header_pages or footer_pages %}
<div class="mt-16 pt-8 border-t border-gray-200 dark:border-gray-700">
<div class="flex flex-wrap justify-center gap-6 text-sm">
<a href="{{ base_url }}shop/products" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
<a href="{{ base_url }}storefront/products" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
Products
</a>
{% for page in (header_pages or footer_pages)[:4] %}
<a href="{{ base_url }}shop/{{ page.slug }}" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
<a href="{{ base_url }}storefront/{{ page.slug }}" class="text-gray-600 dark:text-gray-400 hover:text-primary transition-colors">
{{ page.title }}
</a>
{% endfor %}

View File

@@ -1,7 +1,7 @@
{# app/templates/store/landing-modern.html #}
{# standalone #}
{# Modern Landing Page Template - Feature Rich #}
{% extends "shop/base.html" %}
{% extends "storefront/base.html" %}
{% block title %}{{ store.name }}{% endblock %}
{% block meta_description %}{{ page.meta_description or store.description or store.name }}{% endblock %}
@@ -40,7 +40,7 @@
{# CTAs #}
<div class="flex flex-col sm:flex-row gap-6 justify-center animate-fade-in animation-delay-400">
<a href="{{ base_url }}shop/"
<a href="{{ base_url }}storefront/"
class="group inline-flex items-center justify-center px-10 py-5 text-lg font-bold rounded-xl text-white bg-primary hover:bg-primary-dark transition-all transform hover:scale-105 shadow-2xl hover:shadow-3xl"
style="background-color: var(--color-primary)">
<span>Start Shopping</span>
@@ -137,7 +137,7 @@
<p class="text-xl mb-10 opacity-90">
Explore our collection and find what you're looking for
</p>
<a href="{{ base_url }}shop/products"
<a href="{{ base_url }}storefront/products"
class="inline-flex items-center justify-center px-10 py-5 text-lg font-bold rounded-xl text-primary bg-white hover:bg-gray-50 transition-all transform hover:scale-105 shadow-2xl">
Browse Products
<span class="w-5 h-5 ml-2" x-html="$icon('chevron-right', 'w-5 h-5')"></span>