feat(merchant): extract merchant portal as first-class frontend with auth, Tailwind fixes, and Gitea CI
Some checks failed
CI / ruff (push) Has been cancelled
CI / pytest (push) Has been cancelled
CI / architecture (push) Has been cancelled
CI / dependency-scanning (push) Has been cancelled
CI / audit (push) Has been cancelled
CI / docs (push) Has been cancelled

- Extract login/dashboard from billing module into core (matching admin pattern)
- Add merchant auth API with path-isolated cookies (path=/merchants)
- Add merchant base layout with sidebar/header partials and Alpine.js init
- Add frontend detection and login redirect for MERCHANT type
- Wire merchant token in shared api-client.js (get/clear)
- Migrate billing templates to merchant base with dark mode support
- Fix Tailwind: rename shop→storefront in sources and config
- DRY Makefile tailwind targets with TAILWIND_FRONTENDS loop
- Rebuild all Tailwind outputs (production minified)
- Add Gitea Actions CI workflow (ruff, pytest, architecture, docs)
- Add Gitea deployment documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 20:25:29 +01:00
parent ecb5309879
commit 0437af67ec
31 changed files with 1925 additions and 780 deletions

View File

@@ -59,6 +59,9 @@ class APIClient {
} else if (currentPath.includes('/shop/') || currentPath.startsWith('/api/v1/shop/')) {
token = customerToken;
source = 'customer (path-based)';
} else if (currentPath.startsWith('/merchants/') || currentPath.startsWith('/api/v1/merchants/')) {
token = localStorage.getItem('merchant_token');
source = 'merchant (path-based)';
} else {
// Default fallback for other paths
token = adminToken || storeToken || customerToken;
@@ -382,6 +385,9 @@ class APIClient {
} else if (currentPath.includes('/shop/') || currentPath.startsWith('/api/v1/shop/')) {
apiLog.info('Clearing customer tokens only');
localStorage.removeItem('customer_token');
} else if (currentPath.startsWith('/merchants/') || currentPath.startsWith('/api/v1/merchants/')) {
apiLog.info('Clearing merchant tokens only');
localStorage.removeItem('merchant_token');
} else {
// Fallback: clear all tokens for unknown paths
apiLog.info('Unknown path context, clearing all tokens');