create-nextjs-stack 0.1.1 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +502 -31
  2. package/package.json +6 -1
  3. package/templates/admin/app/(dashboard)/[resource]/[id]/page.tsx +6 -5
  4. package/templates/admin/app/(dashboard)/[resource]/new/page.tsx +11 -12
  5. package/templates/admin/app/(dashboard)/[resource]/page.tsx +4 -3
  6. package/templates/admin/app/actions/upload.ts +0 -7
  7. package/templates/admin/app/globals.css +112 -14
  8. package/templates/admin/app/layout.tsx +4 -1
  9. package/templates/admin/components/admin/Sidebar.tsx +2 -5
  10. package/templates/admin/components.json +22 -0
  11. package/templates/admin/hooks/useResource.ts +3 -0
  12. package/templates/admin/lib/services/resource.service.ts +2 -7
  13. package/templates/admin/lib/supabase/client.ts +8 -4
  14. package/templates/admin/lib/supabase/server.ts +1 -1
  15. package/templates/admin/lib/utils.ts +6 -0
  16. package/templates/admin/middleware.ts +1 -3
  17. package/templates/admin/next.config.ts +10 -2
  18. package/templates/admin/package-lock.json +13 -1
  19. package/templates/admin/package.json +11 -5
  20. package/templates/admin/src/lib/providers/StoreProvider.tsx +12 -0
  21. package/templates/admin/src/store/actions/index.ts +2 -0
  22. package/templates/admin/src/store/hooks.ts +11 -0
  23. package/templates/admin/src/store/index.ts +17 -0
  24. package/templates/admin/src/store/reducers/index.ts +11 -0
  25. package/templates/admin/src/store/types/index.ts +2 -0
  26. package/templates/admin/tsconfig.json +1 -1
  27. package/templates/web/.env.example +5 -1
  28. package/templates/web/package-lock.json +49 -18
  29. package/templates/web/package.json +3 -4
  30. package/templates/web/postcss.config.mjs +3 -1
  31. package/templates/web/src/app/api/revalidate/route.ts +46 -87
  32. package/templates/web/src/app/globals.css +1 -13
  33. package/templates/web/src/app/layout.tsx +4 -46
  34. package/templates/web/src/app/robots.ts +1 -1
  35. package/templates/web/src/app/sitemap.ts +27 -31
  36. package/templates/web/src/lib/seo/metadata.ts +5 -5
  37. package/templates/web/src/lib/seo/seo.config.ts +55 -59
  38. package/templates/web/src/lib/seo/seo.types.ts +1 -7
  39. package/templates/web/src/lib/services/categories.service.ts +3 -3
  40. package/templates/web/src/lib/services/clients.service.ts +2 -2
  41. package/templates/web/src/lib/services/products.service.ts +3 -3
  42. package/templates/web/src/lib/services/projects.service.ts +3 -3
  43. package/templates/web/src/lib/services/users.service.ts +2 -2
  44. package/templates/web/src/lib/supabase/client.ts +1 -1
  45. package/templates/web/src/lib/supabase/server.ts +1 -1
  46. package/templates/web/src/store/hooks.ts +11 -0
  47. package/templates/web/src/store/index.ts +11 -7
  48. package/templates/web/src/store/reducers/index.ts +1 -3
  49. package/templates/admin/app/(dashboard)/categories/[id]/page.tsx +0 -22
  50. package/templates/admin/app/(dashboard)/categories/new/page.tsx +0 -5
  51. package/templates/admin/app/(dashboard)/categories/page.tsx +0 -33
  52. package/templates/admin/app/(dashboard)/clients/[id]/page.tsx +0 -22
  53. package/templates/admin/app/(dashboard)/clients/new/page.tsx +0 -5
  54. package/templates/admin/app/(dashboard)/clients/page.tsx +0 -33
  55. package/templates/admin/app/(dashboard)/products/[id]/page.tsx +0 -22
  56. package/templates/admin/app/(dashboard)/products/new/page.tsx +0 -5
  57. package/templates/admin/app/(dashboard)/products/page.tsx +0 -33
  58. package/templates/admin/app/(dashboard)/projects/[id]/page.tsx +0 -22
  59. package/templates/admin/app/(dashboard)/projects/new/page.tsx +0 -5
  60. package/templates/admin/app/(dashboard)/projects/page.tsx +0 -33
  61. package/templates/admin/app/(dashboard)/users/[id]/page.tsx +0 -22
  62. package/templates/admin/app/(dashboard)/users/new/page.tsx +0 -5
  63. package/templates/admin/app/(dashboard)/users/page.tsx +0 -33
  64. package/templates/admin/components/categories/CategoryForm.tsx +0 -24
  65. package/templates/admin/components/categories/CategoryList.tsx +0 -113
  66. package/templates/admin/components/clients/ClientForm.tsx +0 -24
  67. package/templates/admin/components/clients/ClientList.tsx +0 -113
  68. package/templates/admin/components/products/ProductForm.tsx +0 -24
  69. package/templates/admin/components/products/ProductList.tsx +0 -117
  70. package/templates/admin/components/projects/ProjectForm.tsx +0 -24
  71. package/templates/admin/components/projects/ProjectList.tsx +0 -121
  72. package/templates/admin/components/users/UserForm.tsx +0 -39
  73. package/templates/admin/components/users/UserList.tsx +0 -101
  74. package/templates/web/src/lib/services/categoryService.ts +0 -251
  75. package/templates/web/src/lib/services/clientService.ts +0 -132
  76. package/templates/web/src/lib/services/productService.ts +0 -261
  77. package/templates/web/src/lib/services/projectService.ts +0 -234
  78. package/templates/web/src/lib/utils/cache.ts +0 -98
  79. package/templates/web/src/lib/utils/rate-limiter.ts +0 -102
@@ -1,95 +1,54 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  import { revalidateTag, revalidatePath } from 'next/cache';
3
- import { categoryService } from '@/lib/services/categoryService';
4
- import { productService } from '@/lib/services/productService';
5
- import { clientService } from '@/lib/services/clientService';
6
- import { projectService } from '@/lib/services/projectService';
7
3
 
8
- /**
9
- * On-demand Revalidation API
10
- *
11
- * Usage:
12
- * POST /api/revalidate
13
- * Body: { secret: "your-secret", tag?: "categories|products|clients|projects", path?: "/some-path" }
14
- *
15
- * Example:
16
- * curl -X POST http://localhost:3000/api/revalidate \
17
- * -H "Content-Type: application/json" \
18
- * -d '{"secret":"your-secret","tag":"products"}'
19
- */
20
4
  export async function POST(request: NextRequest) {
21
- try {
22
- const body = await request.json();
23
- const { secret, tag, path } = body;
24
-
25
- // Verify secret
26
- if (!secret || secret !== process.env.REVALIDATION_SECRET) {
27
- return NextResponse.json(
28
- { error: 'Invalid or missing secret' },
29
- { status: 401 }
30
- );
31
- }
32
-
33
- const revalidated: string[] = [];
34
-
35
- // Revalidate by tag
36
- if (tag) {
37
- revalidateTag(tag, 'max');
38
- revalidated.push(`tag:${tag}`);
39
-
40
- // Also invalidate memory cache for the corresponding service
41
- switch (tag) {
42
- case 'categories':
43
- categoryService.invalidateCache();
44
- break;
45
- case 'products':
46
- productService.invalidateCache();
47
- break;
48
- case 'clients':
49
- clientService.invalidateCache();
50
- break;
51
- case 'projects':
52
- projectService.invalidateCache();
53
- break;
54
- default:
55
- console.warn(`[Revalidation] Unknown tag: ${tag}`);
56
- }
57
- }
58
-
59
- // Revalidate by path
60
- if (path) {
61
- revalidatePath(path);
62
- revalidated.push(`path:${path}`);
5
+ try {
6
+ const body = await request.json();
7
+ const { secret, tag, path } = body;
8
+
9
+ if (!secret || secret !== process.env.REVALIDATION_SECRET) {
10
+ return NextResponse.json(
11
+ { error: 'Invalid or missing secret' },
12
+ { status: 401 }
13
+ );
14
+ }
15
+
16
+ const revalidated: string[] = [];
17
+
18
+ if (tag) {
19
+ revalidateTag(tag, 'everything');
20
+ revalidated.push(`tag:${tag}`);
21
+ }
22
+
23
+ if (path) {
24
+ revalidatePath(path);
25
+ revalidated.push(`path:${path}`);
26
+ }
27
+
28
+ if (revalidated.length === 0) {
29
+ return NextResponse.json(
30
+ { error: 'No tag or path specified' },
31
+ { status: 400 }
32
+ );
33
+ }
34
+
35
+ return NextResponse.json({
36
+ revalidated: true,
37
+ items: revalidated,
38
+ timestamp: new Date().toISOString(),
39
+ });
40
+ } catch (error) {
41
+ console.error('[Revalidation] Error:', error);
42
+ return NextResponse.json(
43
+ { error: 'Error revalidating', message: (error as Error).message },
44
+ { status: 500 }
45
+ );
63
46
  }
64
-
65
- if (revalidated.length === 0) {
66
- return NextResponse.json(
67
- { error: 'No tag or path specified' },
68
- { status: 400 }
69
- );
70
- }
71
-
72
- return NextResponse.json({
73
- revalidated: true,
74
- items: revalidated,
75
- timestamp: new Date().toISOString(),
76
- });
77
- } catch (error) {
78
- console.error('[Revalidation] Error:', error);
79
- return NextResponse.json(
80
- {
81
- error: 'Error revalidating',
82
- message: (error as Error).message,
83
- },
84
- { status: 500 }
85
- );
86
- }
87
47
  }
88
48
 
89
- // Optional: GET endpoint to check if the API is working
90
49
  export async function GET() {
91
- return NextResponse.json({
92
- message: 'Revalidation API is running',
93
- usage: 'POST with { secret, tag?, path? }',
94
- });
95
- }
50
+ return NextResponse.json({
51
+ message: 'Revalidation API is running',
52
+ usage: 'POST with { secret, tag?, path? }',
53
+ });
54
+ }
@@ -50,19 +50,7 @@
50
50
  --radius-3xl: calc(var(--radius) + 12px);
51
51
  --radius-4xl: calc(var(--radius) + 16px);
52
52
 
53
- /* Z-Index Hierarchy */
54
- --z-base: 1;
55
- --z-dropdown: 1000;
56
- --z-sticky: 1020;
57
- --z-fixed: 1030;
58
- --z-modal-backdrop: 1040;
59
- --z-modal: 1050;
60
- --z-popover: 1060;
61
- --z-tooltip: 1070;
62
- --z-lightbox: 9999;
63
- --z-lightbox-controls: 10000;
64
-
65
- /* Z-Index Utilities */
53
+ /* Z-Index Scale */
66
54
  --z-base: 1;
67
55
  --z-dropdown: 1000;
68
56
  --z-sticky: 1020;
@@ -1,59 +1,17 @@
1
1
  import type { Metadata, Viewport } from "next";
2
2
  import {
3
- Geist,
4
- Geist_Mono,
5
3
  Inter,
6
- Outfit,
7
- Raleway,
8
- Roboto,
9
- Jersey_10,
10
4
  } from "next/font/google";
11
5
  import "@/app/globals.css";
12
6
  import StoreProvider from "@/lib/providers/StoreProvider";
13
7
  import { GoogleAnalytics } from "@next/third-parties/google";
14
8
 
15
- const geistSans = Geist({
16
- variable: "--font-geist-sans",
17
- subsets: ["latin"],
18
- });
19
-
20
- const geistMono = Geist_Mono({
21
- variable: "--font-geist-mono",
22
- subsets: ["latin"],
23
- });
24
-
25
9
  const inter = Inter({
26
10
  variable: "--font-inter",
27
11
  subsets: ["latin"],
28
12
  display: "swap",
29
13
  });
30
14
 
31
- const roboto = Roboto({
32
- variable: "--font-roboto",
33
- subsets: ["latin"],
34
- weight: ["100", "300", "400", "500", "700", "900"],
35
- display: "swap",
36
- });
37
-
38
- const outfit = Outfit({
39
- variable: "--font-outfit",
40
- subsets: ["latin"],
41
- display: "swap",
42
- });
43
-
44
- const raleway = Raleway({
45
- variable: "--font-raleway",
46
- subsets: ["latin"],
47
- display: "swap",
48
- });
49
-
50
- const jersey10 = Jersey_10({
51
- variable: "--font-jersey-10",
52
- subsets: ["latin"],
53
- weight: "400",
54
- display: "swap",
55
- });
56
-
57
15
  export const viewport: Viewport = {
58
16
  themeColor: [
59
17
  { media: "(prefers-color-scheme: light)", color: "#ffffff" },
@@ -65,7 +23,7 @@ export const viewport: Viewport = {
65
23
  };
66
24
 
67
25
  export const metadata: Metadata = {
68
- metadataBase: new URL("https://create-nextjs-stack.vercel.app"),
26
+ metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000"),
69
27
  title: {
70
28
  default: "Next.js Enterprise Starter",
71
29
  template: "%s | Next.js Enterprise Starter",
@@ -89,7 +47,7 @@ export const metadata: Metadata = {
89
47
  shortcut: "/favicon.png",
90
48
  },
91
49
  alternates: {
92
- canonical: "https://create-nextjs-stack.vercel.app",
50
+ canonical: process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000",
93
51
  },
94
52
  openGraph: {
95
53
  locale: "en_US",
@@ -114,11 +72,11 @@ export default function RootLayout({
114
72
  return (
115
73
  <html lang="en">
116
74
  <body
117
- className={`${geistSans.variable} ${geistMono.variable} ${inter.variable} ${outfit.variable} ${roboto.variable} ${raleway.variable} ${jersey10.variable} antialiased`}
75
+ className={`${inter.variable} antialiased`}
118
76
  >
119
77
  <StoreProvider>
120
78
  {children}
121
- <GoogleAnalytics gaId="G-XYZ1234567" />
79
+ {process.env.NEXT_PUBLIC_GA_ID && <GoogleAnalytics gaId={process.env.NEXT_PUBLIC_GA_ID} />}
122
80
  </StoreProvider>
123
81
  </body>
124
82
  </html>
@@ -7,6 +7,6 @@ export default function robots(): MetadataRoute.Robots {
7
7
  allow: '/',
8
8
  disallow: ['/api/', '/_next/'],
9
9
  },
10
- sitemap: 'https://www.DOMAIN_PLACEHOLDER.com/sitemap.xml',
10
+ sitemap: `${process.env.NEXT_PUBLIC_SITE_URL || 'http://localhost:3000'}/sitemap.xml`,
11
11
  };
12
12
  }
@@ -1,43 +1,35 @@
1
1
  import { MetadataRoute } from 'next';
2
- import { projectService } from '@/lib/services/projectService';
3
- import { productService } from '@/lib/services/productService';
2
+ import { getAdminClient } from '@/lib/supabase/server';
4
3
 
5
4
  export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
6
- const baseUrl = 'https://www.DOMAIN_PLACEHOLDER.com';
5
+ const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://example.com';
7
6
 
8
7
  // Static pages - CUSTOMIZE THESE ROUTES FOR YOUR PROJECT
9
8
  const routes = [
10
9
  '',
11
10
  '/about',
12
- '/products',
13
- '/innovation',
14
- '/services',
15
- '/investors',
16
- '/references',
17
11
  '/contact',
18
- '/impressum',
19
- '/datenschutz',
20
- '/agb'
21
12
  ];
22
13
 
23
- const sitemap: MetadataRoute.Sitemap = [];
14
+ const entries: MetadataRoute.Sitemap = routes.map((route) => ({
15
+ url: `${baseUrl}${route}`,
16
+ lastModified: new Date(),
17
+ changeFrequency: route === '' ? 'daily' : 'weekly',
18
+ priority: route === '' ? 1.0 : route === '/contact' ? 0.9 : 0.8,
19
+ }));
24
20
 
25
- // Generate entries for each route
26
- routes.forEach((route) => {
27
- sitemap.push({
28
- url: `${baseUrl}${route}`,
29
- lastModified: new Date(),
30
- changeFrequency: route === '' ? 'daily' : 'weekly',
31
- priority: route === '' ? 1.0 : (route === '/contact' ? 0.9 : 0.8),
32
- });
33
- });
21
+ const supabase = await getAdminClient();
34
22
 
35
- // Dynamic Projects
23
+ // Dynamic Projects - CUSTOMIZE TABLE AND SLUG FIELD FOR YOUR PROJECT
36
24
  try {
37
- const projectSlugs = await projectService.getAllSlugs();
38
- projectSlugs.forEach((slug) => {
39
- sitemap.push({
40
- url: `${baseUrl}/references/${slug}`,
25
+ const { data: projects } = await supabase
26
+ .from('projects')
27
+ .select('slug')
28
+ .eq('published', true);
29
+
30
+ projects?.forEach(({ slug }) => {
31
+ entries.push({
32
+ url: `${baseUrl}/projects/${slug}`,
41
33
  lastModified: new Date(),
42
34
  changeFrequency: 'weekly',
43
35
  priority: 0.7,
@@ -47,11 +39,15 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
47
39
  console.error('[Sitemap] Error fetching project slugs:', error);
48
40
  }
49
41
 
50
- // Dynamic Products
42
+ // Dynamic Products - CUSTOMIZE TABLE AND SLUG FIELD FOR YOUR PROJECT
51
43
  try {
52
- const productSlugs = await productService.getAllSlugs();
53
- productSlugs.forEach((slug) => {
54
- sitemap.push({
44
+ const { data: products } = await supabase
45
+ .from('products')
46
+ .select('slug')
47
+ .eq('published', true);
48
+
49
+ products?.forEach(({ slug }) => {
50
+ entries.push({
55
51
  url: `${baseUrl}/products/${slug}`,
56
52
  lastModified: new Date(),
57
53
  changeFrequency: 'weekly',
@@ -62,5 +58,5 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
62
58
  console.error('[Sitemap] Error fetching product slugs:', error);
63
59
  }
64
60
 
65
- return sitemap;
61
+ return entries;
66
62
  }
@@ -88,16 +88,16 @@ export function generateOrganizationSchema() {
88
88
  url: site.siteUrl,
89
89
  logo: `${site.siteUrl}/images/logo.png`,
90
90
  description:
91
- 'Eurodeco Panel Systems GmbH - Innovative Panel-Systeme für Architektur der Zukunft',
91
+ 'Your Company Name - Generic description for your business',
92
92
  contactPoint: {
93
93
  '@type': 'ContactPoint',
94
94
  contactType: 'Sales',
95
- availableLanguage: ['German', 'English'],
95
+ availableLanguage: ['English', 'German'],
96
96
  },
97
97
  sameAs: [
98
- // Sosyal medya linklerinizi buraya ekleyin
99
- // 'https://www.linkedin.com/company/eurodeco-panel-systems',
100
- // 'https://www.instagram.com/eurodeco',
98
+ // Add your social media links here
99
+ // 'https://www.linkedin.com/company/yourcompany',
100
+ // 'https://www.instagram.com/yourcompany',
101
101
  ],
102
102
  };
103
103
  }
@@ -6,42 +6,39 @@ import { SEOConfig } from './seo.types';
6
6
  */
7
7
  export const seoConfig: SEOConfig = {
8
8
  site: {
9
- siteName: 'Eurodeco Panel Systems GmbH',
10
- siteUrl: 'https://www.eurodecopanel.de',
11
- defaultLocale: 'de',
12
- locales: ['de', 'en'],
9
+ siteName: 'Your Company Name',
10
+ siteUrl: 'https://www.yourdomain.com',
11
+ defaultLocale: 'en',
12
+ locales: ['en', 'de'],
13
13
  defaultOGImage: '/images/og-default.jpg',
14
- twitterHandle: '@eurodecopanel', // Placeholder handle
14
+ twitterHandle: '@yourhandle', // Placeholder handle
15
15
  },
16
16
 
17
17
  pages: {
18
18
  // Home Page SEO
19
19
  home: {
20
- title: 'Eurodeco Panel Systems GmbH - Innovative Panel-Systeme',
20
+ title: 'Your Company Name - Catchy Slogan Here',
21
21
  description:
22
- 'Eurodeco Panel Systems GmbH entwickelt und vertreibt moderne Hochleistungs-Paneelsysteme für anspruchsvolle Architektur, Innenausbau und Gewerbeprojekte.',
22
+ 'Your company description goes here. Explain what you do, who you serve, and why you are the best choice for your customers.',
23
23
  keywords: [
24
- 'Eurodeco',
25
- 'Panel-Systeme',
26
- 'Wandpaneele',
27
- 'Deckenpaneele',
28
- 'Brandschutz',
29
- 'Leichtbau',
30
- 'Architektur',
31
- 'Gewerbeprojekte',
24
+ 'Keyword 1',
25
+ 'Keyword 2',
26
+ 'Keyword 3',
27
+ 'Keyword 4',
28
+ 'Keyword 5',
32
29
  ],
33
30
  openGraph: {
34
- title: 'Eurodeco Panel Systems GmbH - Innovative Panel-Systeme',
31
+ title: 'Your Company Name - Catchy Slogan Here',
35
32
  description:
36
- 'Entwickelt und vertreibt moderne Hochleistungs-Paneelsysteme für anspruchsvolle Architektur.',
33
+ 'Your short company description for social media sharing goes here.',
37
34
  images: ['/images/og-home.jpg'],
38
35
  type: 'website',
39
36
  },
40
37
  twitter: {
41
38
  card: 'summary_large_image',
42
- title: 'Eurodeco Panel Systems GmbH - Innovative Panel-Systeme',
39
+ title: 'Your Company Name - Catchy Slogan Here',
43
40
  description:
44
- 'Entwickelt und vertreibt moderne Hochleistungs-Paneelsysteme für anspruchsvolle Architektur.',
41
+ 'Your short company description for Twitter sharing goes here.',
45
42
  images: ['/images/twitter-home.jpg'],
46
43
  },
47
44
  robots: {
@@ -56,22 +53,21 @@ export const seoConfig: SEOConfig = {
56
53
 
57
54
  // About Page SEO
58
55
  about: {
59
- title: 'Über Uns - Eurodeco Panel Systems GmbH',
56
+ title: 'About Us - Your Company Name',
60
57
  description:
61
- 'Erfahren Sie mehr über Eurodeco Panel Systems GmbH, unsere Mission, Vision und Technologie für moderne Paneelsysteme.',
58
+ 'Learn more about Your Company Name, our mission, vision, and the technology behind our products and services.',
62
59
  keywords: [
63
- 'Über Eurodeco',
64
- 'Mission',
65
- 'Vision',
66
- 'Technologie',
67
- 'Paneelsysteme',
68
- 'Unternehmensprofil',
60
+ 'About Us',
61
+ 'Company Mission',
62
+ 'Company Vision',
63
+ 'Our Technology',
64
+ 'Company Profile',
69
65
  ],
70
- canonical: 'https://www.eurodecopanel.de/about',
66
+ canonical: 'https://www.yourdomain.com/about',
71
67
  openGraph: {
72
- title: 'Über Uns - Eurodeco Panel Systems GmbH',
68
+ title: 'About Us - Your Company Name',
73
69
  description:
74
- 'Erfahren Sie mehr über Eurodeco Panel Systems GmbH und unsere innovativen Lösungen.',
70
+ 'Learn more about Your Company Name and our innovative solutions.',
75
71
  images: ['/images/og-about.jpg'],
76
72
  type: 'website',
77
73
  },
@@ -83,21 +79,21 @@ export const seoConfig: SEOConfig = {
83
79
 
84
80
  // Works/Projects Page SEO
85
81
  works: {
86
- title: 'Referenzen - Eurodeco Panel Systems GmbH',
82
+ title: 'Our Work - Your Company Name',
87
83
  description:
88
- 'Entdecken Sie unsere erfolgreichen Projekte und Referenzen in den Bereichen Gewerbe, Büro, Hotel und öffentliche Gebäude.',
84
+ 'Discover our successful projects and references across various industries and domains.',
89
85
  keywords: [
90
- 'Referenzen',
91
- 'Projekte',
92
- 'Eurodeco Projekte',
93
- 'Architektur Referenzen',
94
- 'Bauprojekte',
86
+ 'References',
87
+ 'Projects',
88
+ 'Our Work',
89
+ 'Portfolio',
90
+ 'Case Studies',
95
91
  ],
96
- canonical: 'https://www.eurodecopanel.de/references',
92
+ canonical: 'https://www.yourdomain.com/references',
97
93
  openGraph: {
98
- title: 'Referenzen - Eurodeco Panel Systems GmbH',
94
+ title: 'Our Work - Your Company Name',
99
95
  description:
100
- 'Entdecken Sie unsere erfolgreichen Projekte und Referenzen.',
96
+ 'Discover our successful projects and references.',
101
97
  images: ['/images/og-works.jpg'],
102
98
  type: 'website',
103
99
  },
@@ -109,20 +105,20 @@ export const seoConfig: SEOConfig = {
109
105
 
110
106
  // Blog Page SEO (Keeping structurally but updating content generic/german if needed, or removing if not in list. Task.md didn't ask to remove, just update config. I'll translate to German generic).
111
107
  blog: {
112
- title: 'Aktuelles - Eurodeco Panel Systems GmbH',
108
+ title: 'Blog - Your Company Name',
113
109
  description:
114
- 'Neuigkeiten und Trends zu Paneelsystemen, Architektur und Innovationen von Eurodeco.',
110
+ 'News, trends, and insights about our industry and innovations from Your Company Name.',
115
111
  keywords: [
116
- 'Eurodeco News',
117
- 'Architektur Trends',
118
- 'Paneel Innovationen',
119
- 'Baubranche',
112
+ 'Company News',
113
+ 'Industry Trends',
114
+ 'Innovations',
115
+ 'Blog',
120
116
  ],
121
- canonical: 'https://www.eurodecopanel.de/blog',
117
+ canonical: 'https://www.yourdomain.com/blog',
122
118
  openGraph: {
123
- title: 'Aktuelles - Eurodeco Panel Systems GmbH',
119
+ title: 'Blog - Your Company Name',
124
120
  description:
125
- 'Neuigkeiten und Trends zu Paneelsystemen und Architektur.',
121
+ 'News, trends, and insights about our industry and architecture.',
126
122
  images: ['/images/og-blog.jpg'],
127
123
  type: 'website',
128
124
  },
@@ -134,21 +130,21 @@ export const seoConfig: SEOConfig = {
134
130
 
135
131
  // Contact Page SEO
136
132
  contact: {
137
- title: 'Kontakt - Eurodeco Panel Systems GmbH',
133
+ title: 'Contact - Your Company Name',
138
134
  description:
139
- 'Kontaktieren Sie Eurodeco Panel Systems GmbH für Ihr nächstes Architektur- oder Bauprojekt. Wir freuen uns auf den Austausch.',
135
+ 'Contact Your Company Name for your next project. We look forward to hearing from you.',
140
136
  keywords: [
141
- 'Kontakt Eurodeco',
142
- 'Anfrage',
143
- 'Projekt starten',
144
- 'Eurodeco Adresse',
145
- 'Eurodeco Email',
137
+ 'Contact Us',
138
+ 'Inquiry',
139
+ 'Start Project',
140
+ 'Company Address',
141
+ 'Company Email',
146
142
  ],
147
- canonical: 'https://www.eurodecopanel.de/contact',
143
+ canonical: 'https://www.yourdomain.com/contact',
148
144
  openGraph: {
149
- title: 'Kontakt - Eurodeco Panel Systems GmbH',
145
+ title: 'Contact - Your Company Name',
150
146
  description:
151
- 'Kontaktieren Sie uns für Ihr nächstes Projekt.',
147
+ 'Contact us for your next project.',
152
148
  images: ['/images/og-contact.jpg'],
153
149
  type: 'website',
154
150
  },
@@ -66,11 +66,5 @@ export interface SiteSEOConfig {
66
66
  */
67
67
  export interface SEOConfig {
68
68
  site: SiteSEOConfig;
69
- pages: {
70
- home: PageSEOConfig;
71
- about: PageSEOConfig;
72
- works: PageSEOConfig;
73
- blog: PageSEOConfig;
74
- contact: PageSEOConfig;
75
- };
69
+ pages: Record<string, PageSEOConfig>;
76
70
  }
@@ -1,10 +1,10 @@
1
- import { getServerClient } from "@/lib/supabase/server";
1
+ import { getAdminClient } from "@/lib/supabase/server";
2
2
 
3
3
  export class CategoryService {
4
4
  private static table = "categories";
5
5
 
6
6
  static async getAll() {
7
- const supabase = await getServerClient();
7
+ const supabase = await getAdminClient();
8
8
  const { data, error } = await supabase
9
9
  .from(this.table)
10
10
  .select("*")
@@ -20,7 +20,7 @@ export class CategoryService {
20
20
  }
21
21
 
22
22
  static async getBySlug(slug: string) {
23
- const supabase = await getServerClient();
23
+ const supabase = await getAdminClient();
24
24
  const { data, error } = await supabase
25
25
  .from(this.table)
26
26
  .select("*")
@@ -1,10 +1,10 @@
1
- import { getServerClient } from "@/lib/supabase/server";
1
+ import { getAdminClient } from "@/lib/supabase/server";
2
2
 
3
3
  export class ClientService {
4
4
  private static table = "clients";
5
5
 
6
6
  static async getAll() {
7
- const supabase = await getServerClient();
7
+ const supabase = await getAdminClient();
8
8
  const { data, error } = await supabase
9
9
  .from(this.table)
10
10
  .select("*")
@@ -1,10 +1,10 @@
1
- import { getServerClient } from "@/lib/supabase/server";
1
+ import { getAdminClient } from "@/lib/supabase/server";
2
2
 
3
3
  export class ProductService {
4
4
  private static table = "products";
5
5
 
6
6
  static async getAll() {
7
- const supabase = await getServerClient();
7
+ const supabase = await getAdminClient();
8
8
  const { data, error } = await supabase
9
9
  .from(this.table)
10
10
  .select("*, categories(title, slug)")
@@ -20,7 +20,7 @@ export class ProductService {
20
20
  }
21
21
 
22
22
  static async getBySlug(slug: string) {
23
- const supabase = await getServerClient();
23
+ const supabase = await getAdminClient();
24
24
  const { data, error } = await supabase
25
25
  .from(this.table)
26
26
  .select("*, categories(title, slug)")