create-nextjs-stack 0.1.0

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 (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/bin/cli.js +187 -0
  4. package/package.json +48 -0
  5. package/templates/admin/.env.example +11 -0
  6. package/templates/admin/README.md +82 -0
  7. package/templates/admin/app/(auth)/login/page.tsx +84 -0
  8. package/templates/admin/app/(dashboard)/[resource]/[id]/page.tsx +45 -0
  9. package/templates/admin/app/(dashboard)/[resource]/new/page.tsx +32 -0
  10. package/templates/admin/app/(dashboard)/[resource]/page.tsx +131 -0
  11. package/templates/admin/app/(dashboard)/categories/[id]/page.tsx +22 -0
  12. package/templates/admin/app/(dashboard)/categories/new/page.tsx +5 -0
  13. package/templates/admin/app/(dashboard)/categories/page.tsx +33 -0
  14. package/templates/admin/app/(dashboard)/clients/[id]/page.tsx +22 -0
  15. package/templates/admin/app/(dashboard)/clients/new/page.tsx +5 -0
  16. package/templates/admin/app/(dashboard)/clients/page.tsx +33 -0
  17. package/templates/admin/app/(dashboard)/dashboard/page.tsx +45 -0
  18. package/templates/admin/app/(dashboard)/layout.tsx +13 -0
  19. package/templates/admin/app/(dashboard)/products/[id]/page.tsx +22 -0
  20. package/templates/admin/app/(dashboard)/products/new/page.tsx +5 -0
  21. package/templates/admin/app/(dashboard)/products/page.tsx +33 -0
  22. package/templates/admin/app/(dashboard)/projects/[id]/page.tsx +22 -0
  23. package/templates/admin/app/(dashboard)/projects/new/page.tsx +5 -0
  24. package/templates/admin/app/(dashboard)/projects/page.tsx +33 -0
  25. package/templates/admin/app/(dashboard)/users/[id]/page.tsx +22 -0
  26. package/templates/admin/app/(dashboard)/users/new/page.tsx +5 -0
  27. package/templates/admin/app/(dashboard)/users/page.tsx +33 -0
  28. package/templates/admin/app/actions/resources.ts +46 -0
  29. package/templates/admin/app/actions/upload.ts +58 -0
  30. package/templates/admin/app/favicon.ico +0 -0
  31. package/templates/admin/app/globals.css +23 -0
  32. package/templates/admin/app/layout.tsx +23 -0
  33. package/templates/admin/app/page.tsx +5 -0
  34. package/templates/admin/components/admin/AdminLayoutClient.tsx +22 -0
  35. package/templates/admin/components/admin/DeleteModal.tsx +90 -0
  36. package/templates/admin/components/admin/FormLayout.tsx +113 -0
  37. package/templates/admin/components/admin/ImageUpload.tsx +137 -0
  38. package/templates/admin/components/admin/ResourceFormClient.tsx +62 -0
  39. package/templates/admin/components/admin/Sidebar.tsx +74 -0
  40. package/templates/admin/components/admin/SubmitButton.tsx +34 -0
  41. package/templates/admin/components/admin/ToastProvider.tsx +8 -0
  42. package/templates/admin/components/categories/CategoryForm.tsx +24 -0
  43. package/templates/admin/components/categories/CategoryList.tsx +113 -0
  44. package/templates/admin/components/clients/ClientForm.tsx +24 -0
  45. package/templates/admin/components/clients/ClientList.tsx +113 -0
  46. package/templates/admin/components/products/ProductForm.tsx +24 -0
  47. package/templates/admin/components/products/ProductList.tsx +117 -0
  48. package/templates/admin/components/projects/ProjectForm.tsx +24 -0
  49. package/templates/admin/components/projects/ProjectList.tsx +121 -0
  50. package/templates/admin/components/users/UserForm.tsx +39 -0
  51. package/templates/admin/components/users/UserList.tsx +101 -0
  52. package/templates/admin/config/resources.ts +123 -0
  53. package/templates/admin/eslint.config.mjs +18 -0
  54. package/templates/admin/hooks/useResource.ts +86 -0
  55. package/templates/admin/lib/services/base.service.ts +106 -0
  56. package/templates/admin/lib/services/categories.service.ts +7 -0
  57. package/templates/admin/lib/services/clients.service.ts +7 -0
  58. package/templates/admin/lib/services/index.ts +27 -0
  59. package/templates/admin/lib/services/products.service.ts +9 -0
  60. package/templates/admin/lib/services/projects.service.ts +22 -0
  61. package/templates/admin/lib/services/resource.service.ts +26 -0
  62. package/templates/admin/lib/services/users.service.ts +9 -0
  63. package/templates/admin/lib/supabase/client.ts +9 -0
  64. package/templates/admin/lib/supabase/middleware.ts +57 -0
  65. package/templates/admin/lib/supabase/server.ts +29 -0
  66. package/templates/admin/middleware.ts +15 -0
  67. package/templates/admin/next.config.ts +10 -0
  68. package/templates/admin/package-lock.json +6768 -0
  69. package/templates/admin/package.json +33 -0
  70. package/templates/admin/postcss.config.mjs +7 -0
  71. package/templates/admin/public/file.svg +1 -0
  72. package/templates/admin/public/globe.svg +1 -0
  73. package/templates/admin/public/next.svg +1 -0
  74. package/templates/admin/public/vercel.svg +1 -0
  75. package/templates/admin/public/window.svg +1 -0
  76. package/templates/admin/supabase_mock_data.sql +57 -0
  77. package/templates/admin/supabase_schema.sql +93 -0
  78. package/templates/admin/tsconfig.json +34 -0
  79. package/templates/web/.env.example +21 -0
  80. package/templates/web/README.md +129 -0
  81. package/templates/web/components.json +22 -0
  82. package/templates/web/eslint.config.mjs +25 -0
  83. package/templates/web/next.config.ts +25 -0
  84. package/templates/web/package-lock.json +6778 -0
  85. package/templates/web/package.json +45 -0
  86. package/templates/web/postcss.config.mjs +5 -0
  87. package/templates/web/src/app/api/contact/route.ts +181 -0
  88. package/templates/web/src/app/api/revalidate/route.ts +95 -0
  89. package/templates/web/src/app/error.tsx +28 -0
  90. package/templates/web/src/app/globals.css +838 -0
  91. package/templates/web/src/app/layout.tsx +126 -0
  92. package/templates/web/src/app/loading.tsx +60 -0
  93. package/templates/web/src/app/not-found.tsx +68 -0
  94. package/templates/web/src/app/page.tsx +106 -0
  95. package/templates/web/src/app/robots.ts +12 -0
  96. package/templates/web/src/app/sitemap.ts +66 -0
  97. package/templates/web/src/components/home/StatsGrid.tsx +89 -0
  98. package/templates/web/src/hooks/useIntersectionObserver.ts +39 -0
  99. package/templates/web/src/lib/providers/StoreProvider.tsx +12 -0
  100. package/templates/web/src/lib/seo/index.ts +4 -0
  101. package/templates/web/src/lib/seo/metadata.ts +103 -0
  102. package/templates/web/src/lib/seo/seo.config.ts +161 -0
  103. package/templates/web/src/lib/seo/seo.types.ts +76 -0
  104. package/templates/web/src/lib/services/categories.service.ts +38 -0
  105. package/templates/web/src/lib/services/categoryService.ts +251 -0
  106. package/templates/web/src/lib/services/clientService.ts +132 -0
  107. package/templates/web/src/lib/services/clients.service.ts +20 -0
  108. package/templates/web/src/lib/services/productService.ts +261 -0
  109. package/templates/web/src/lib/services/products.service.ts +38 -0
  110. package/templates/web/src/lib/services/projectService.ts +234 -0
  111. package/templates/web/src/lib/services/projects.service.ts +38 -0
  112. package/templates/web/src/lib/services/users.service.ts +20 -0
  113. package/templates/web/src/lib/supabase/client.ts +42 -0
  114. package/templates/web/src/lib/supabase/constants.ts +25 -0
  115. package/templates/web/src/lib/supabase/server.ts +29 -0
  116. package/templates/web/src/lib/supabase/types.ts +112 -0
  117. package/templates/web/src/lib/utils/cache.ts +98 -0
  118. package/templates/web/src/lib/utils/rate-limiter.ts +102 -0
  119. package/templates/web/src/store/actions/index.ts +2 -0
  120. package/templates/web/src/store/index.ts +13 -0
  121. package/templates/web/src/store/reducers/index.ts +13 -0
  122. package/templates/web/src/store/types/index.ts +2 -0
  123. package/templates/web/tsconfig.json +41 -0
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "supabase-admin-template",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "start": "next start",
9
+ "lint": "eslint"
10
+ },
11
+ "dependencies": {
12
+ "@supabase/ssr": "^0.8.0",
13
+ "@supabase/supabase-js": "^2.94.1",
14
+ "cloudinary": "^2.9.0",
15
+ "lucide-react": "^0.563.0",
16
+ "next": "16.1.6",
17
+ "react": "19.2.3",
18
+ "react-dom": "19.2.3",
19
+ "react-hook-form": "^7.71.1",
20
+ "react-toastify": "^11.0.3"
21
+ },
22
+ "devDependencies": {
23
+ "@tailwindcss/postcss": "^4",
24
+ "@types/node": "^20",
25
+ "@types/react": "^19",
26
+ "@types/react-dom": "^19",
27
+ "babel-plugin-react-compiler": "1.0.0",
28
+ "eslint": "^9",
29
+ "eslint-config-next": "16.1.6",
30
+ "tailwindcss": "^4",
31
+ "typescript": "^5"
32
+ }
33
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
@@ -0,0 +1,57 @@
1
+ -- Mock Data Script for Admin Panel
2
+ -- Run this script in the Supabase SQL Editor to populate your tables with test data.
3
+
4
+ -- 1. Insert Users
5
+ -- Note: These users won't have login credentials in auth.users, they are just profile records.
6
+ INSERT INTO public.users (email, full_name, role) VALUES
7
+ ('admin@example.com', 'Test Admin User', 'admin'),
8
+ ('editor1@example.com', 'Test Editor One', 'editor'),
9
+ ('editor2@example.com', 'Test Editor Two', 'editor');
10
+
11
+ -- 2. Insert Categories
12
+ INSERT INTO public.categories (title, slug, description, featured, published) VALUES
13
+ ('Test Category 1', 'test-category-1', 'Description for Test Category 1', true, true),
14
+ ('Test Category 2', 'test-category-2', 'Description for Test Category 2', false, true),
15
+ ('Test Category 3', 'test-category-3', 'Description for Test Category 3', true, true),
16
+ ('Test Category 4', 'test-category-4', 'Description for Test Category 4', false, false),
17
+ ('Test Category 5', 'test-category-5', 'Description for Test Category 5', false, true);
18
+
19
+ -- 3. Insert Clients
20
+ INSERT INTO public.clients (name, logo_url, website) VALUES
21
+ ('Test Client 1', 'https://picsum.photos/200/200?random=1', 'https://example.com/client1'),
22
+ ('Test Client 2', 'https://picsum.photos/200/200?random=2', 'https://example.com/client2'),
23
+ ('Test Client 3', 'https://picsum.photos/200/200?random=3', 'https://example.com/client3'),
24
+ ('Test Client 4', 'https://picsum.photos/200/200?random=4', 'https://example.com/client4'),
25
+ ('Test Client 5', 'https://picsum.photos/200/200?random=5', 'https://example.com/client5');
26
+
27
+ -- 4. Insert Products (Assigning to randomly selected Categories)
28
+ WITH cat_ids AS (
29
+ SELECT id, row_number() OVER () as rn FROM public.categories
30
+ )
31
+ INSERT INTO public.products (title, slug, description, featured_image_url, category_id, featured, published) VALUES
32
+ ('Test Product 1', 'test-product-1', 'Description for Test Product 1', 'https://picsum.photos/800/600?random=10', (SELECT id FROM cat_ids WHERE rn = 1), true, true),
33
+ ('Test Product 2', 'test-product-2', 'Description for Test Product 2', 'https://picsum.photos/800/600?random=11', (SELECT id FROM cat_ids WHERE rn = 2), false, true),
34
+ ('Test Product 3', 'test-product-3', 'Description for Test Product 3', 'https://picsum.photos/800/600?random=12', (SELECT id FROM cat_ids WHERE rn = 3), true, true),
35
+ ('Test Product 4', 'test-product-4', 'Description for Test Product 4', 'https://picsum.photos/800/600?random=13', (SELECT id FROM cat_ids WHERE rn = 4), false, false),
36
+ ('Test Product 5', 'test-product-5', 'Description for Test Product 5', 'https://picsum.photos/800/600?random=14', (SELECT id FROM cat_ids WHERE rn = 5), true, true),
37
+ ('Test Product 6', 'test-product-6', 'Description for Test Product 6', 'https://picsum.photos/800/600?random=15', (SELECT id FROM cat_ids WHERE rn = 1), false, true),
38
+ ('Test Product 7', 'test-product-7', 'Description for Test Product 7', 'https://picsum.photos/800/600?random=16', (SELECT id FROM cat_ids WHERE rn = 2), true, true),
39
+ ('Test Product 8', 'test-product-8', 'Description for Test Product 8', 'https://picsum.photos/800/600?random=17', (SELECT id FROM cat_ids WHERE rn = 3), false, true),
40
+ ('Test Product 9', 'test-product-9', 'Description for Test Product 9', 'https://picsum.photos/800/600?random=18', (SELECT id FROM cat_ids WHERE rn = 4), true, true),
41
+ ('Test Product 10', 'test-product-10', 'Description for Test Product 10', 'https://picsum.photos/800/600?random=19', (SELECT id FROM cat_ids WHERE rn = 5), false, true);
42
+
43
+ -- 5. Insert Projects (Assigning to randomly selected Clients)
44
+ WITH client_ids AS (
45
+ SELECT id, row_number() OVER () as rn FROM public.clients
46
+ )
47
+ INSERT INTO public.projects (title, slug, description, featured_image_url, client_id, published) VALUES
48
+ ('Test Project 1', 'test-project-1', 'Description for Test Project 1', 'https://picsum.photos/800/600?random=30', (SELECT id FROM client_ids WHERE rn = 1), true),
49
+ ('Test Project 2', 'test-project-2', 'Description for Test Project 2', 'https://picsum.photos/800/600?random=31', (SELECT id FROM client_ids WHERE rn = 2), true),
50
+ ('Test Project 3', 'test-project-3', 'Description for Test Project 3', 'https://picsum.photos/800/600?random=32', (SELECT id FROM client_ids WHERE rn = 3), true),
51
+ ('Test Project 4', 'test-project-4', 'Description for Test Project 4', 'https://picsum.photos/800/600?random=33', (SELECT id FROM client_ids WHERE rn = 4), false),
52
+ ('Test Project 5', 'test-project-5', 'Description for Test Project 5', 'https://picsum.photos/800/600?random=34', (SELECT id FROM client_ids WHERE rn = 5), true),
53
+ ('Test Project 6', 'test-project-6', 'Description for Test Project 6', 'https://picsum.photos/800/600?random=35', (SELECT id FROM client_ids WHERE rn = 1), true),
54
+ ('Test Project 7', 'test-project-7', 'Description for Test Project 7', 'https://picsum.photos/800/600?random=36', (SELECT id FROM client_ids WHERE rn = 2), true),
55
+ ('Test Project 8', 'test-project-8', 'Description for Test Project 8', 'https://picsum.photos/800/600?random=37', (SELECT id FROM client_ids WHERE rn = 3), true),
56
+ ('Test Project 9', 'test-project-9', 'Description for Test Project 9', 'https://picsum.photos/800/600?random=38', (SELECT id FROM client_ids WHERE rn = 4), true),
57
+ ('Test Project 10', 'test-project-10', 'Description for Test Project 10', 'https://picsum.photos/800/600?random=39', (SELECT id FROM client_ids WHERE rn = 5), true);
@@ -0,0 +1,93 @@
1
+ -- Enable UUID extension
2
+ create extension if not exists "uuid-ossp";
3
+
4
+ -- 1. Categories Table
5
+ create table if not exists public.categories (
6
+ id uuid primary key default uuid_generate_v4(),
7
+ created_at timestamp with time zone default timezone('utc'::text, now()) not null,
8
+ updated_at timestamp with time zone default timezone('utc'::text, now()) not null,
9
+ title text not null,
10
+ slug text not null unique,
11
+ description text,
12
+ featured boolean default false,
13
+ published boolean default true
14
+ );
15
+
16
+ -- 2. Clients Table
17
+ create table if not exists public.clients (
18
+ id uuid primary key default uuid_generate_v4(),
19
+ created_at timestamp with time zone default timezone('utc'::text, now()) not null,
20
+ updated_at timestamp with time zone default timezone('utc'::text, now()) not null,
21
+ name text not null,
22
+ logo_url text,
23
+ website text
24
+ );
25
+
26
+ -- 3. Products Table
27
+ create table if not exists public.products (
28
+ id uuid primary key default uuid_generate_v4(),
29
+ created_at timestamp with time zone default timezone('utc'::text, now()) not null,
30
+ updated_at timestamp with time zone default timezone('utc'::text, now()) not null,
31
+ title text not null,
32
+ slug text not null unique,
33
+ description text,
34
+ featured_image_url text,
35
+ category_id uuid references public.categories(id) on delete set null,
36
+ featured boolean default false,
37
+ published boolean default true
38
+ );
39
+
40
+ -- 4. Projects Table
41
+ create table if not exists public.projects (
42
+ id uuid primary key default uuid_generate_v4(),
43
+ created_at timestamp with time zone default timezone('utc'::text, now()) not null,
44
+ updated_at timestamp with time zone default timezone('utc'::text, now()) not null,
45
+ title text not null,
46
+ slug text not null unique,
47
+ description text,
48
+ client_id uuid references public.clients(id) on delete set null,
49
+ featured_image_url text,
50
+ published boolean default true
51
+ );
52
+
53
+ -- 5. Users Table (Public Profile / Admin Management)
54
+ -- Note: This is separate from auth.users, used for application logic
55
+ create table if not exists public.users (
56
+ id uuid primary key default uuid_generate_v4(),
57
+ created_at timestamp with time zone default timezone('utc'::text, now()) not null,
58
+ updated_at timestamp with time zone default timezone('utc'::text, now()) not null,
59
+ email text not null unique,
60
+ full_name text,
61
+ role text default 'editor' check (role in ('admin', 'editor'))
62
+ );
63
+
64
+ -- Enable Row Level Security (RLS) on all tables
65
+ alter table public.categories enable row level security;
66
+ alter table public.clients enable row level security;
67
+ alter table public.products enable row level security;
68
+ alter table public.projects enable row level security;
69
+ alter table public.users enable row level security;
70
+
71
+ -- Create policies (modify as needed for your auth model)
72
+ -- For development/admin, we might want full access for authenticated users
73
+
74
+ create policy "Enable all access for authenticated users" on public.categories for all using (auth.role() = 'authenticated');
75
+ create policy "Enable all access for authenticated users" on public.clients for all using (auth.role() = 'authenticated');
76
+ create policy "Enable all access for authenticated users" on public.products for all using (auth.role() = 'authenticated');
77
+ create policy "Enable all access for authenticated users" on public.projects for all using (auth.role() = 'authenticated');
78
+ create policy "Enable all access for authenticated users" on public.users for all using (auth.role() = 'authenticated');
79
+
80
+ -- Function to automatically update updated_at timestamp
81
+ create or replace function public.handle_new_user()
82
+ returns trigger as $$
83
+ begin
84
+ insert into public.users (id, email, full_name, role)
85
+ values (new.id, new.email, new.raw_user_meta_data->>'full_name', 'admin');
86
+ return new;
87
+ end;
88
+ $$ language plpgsql security definer;
89
+
90
+ -- Trigger to call the function on new user creation
91
+ create trigger on_auth_user_created
92
+ after insert on auth.users
93
+ for each row execute procedure public.handle_new_user();
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }
@@ -0,0 +1,21 @@
1
+ # Email Service (Resend)
2
+ RESEND_API_KEY=your_resend_api_key_here
3
+ RESEND_FROM_EMAIL=your_resend_from_email_here
4
+
5
+ # Supabase Configuration
6
+ SUPABASE_DATABASE_PASSWORD=your_supabase_database_password_here
7
+ SUPABASE_PROJECT_NAME=your_supabase_project_name_here
8
+ SUPABASE_PROJECT_ID=your_supabase_project_id_here
9
+ NEXT_PUBLIC_SUPABASE_URL=your_supabase_url_here
10
+ SUPABASE_PUBLISHABLE_KEY=your_supabase_publishable_key_here
11
+ SUPABASE_SECRET_KEY=your_supabase_secret_key_here
12
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key_here
13
+ SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key_here
14
+ REVALIDATION_SECRET=your_revalidation_secret_here
15
+
16
+ # Cloudinary Configuration
17
+ CLOUDINARY_API_KEY=your_cloudinary_api_key_here
18
+ CLOUDINARY_API_SECRET=your_cloudinary_api_secret_here
19
+ CLOUDINARY_ID=your_cloud_name_here
20
+ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your_cloud_name_here
21
+ CLOUDINARY_URL=cloudinary://your_api_key:your_api_secret@your_cloud_name
@@ -0,0 +1,129 @@
1
+ # Next.js Project Template
2
+
3
+ A production-ready Next.js template with modern tech stack and best practices for building corporate websites and web applications.
4
+
5
+ ## 🚀 Technology Stack
6
+
7
+ - **Framework**: [Next.js 16](https://nextjs.org/) with App Router & Turbopack
8
+ - **Styling**: [Tailwind CSS 4](https://tailwindcss.com/)
9
+ - **State Management**: [Redux Toolkit](https://redux-toolkit.js.org/)
10
+ - **Database**: [Supabase](https://supabase.com/) (PostgreSQL + Auth + Storage)
11
+ - **Media Management**: [Cloudinary](https://cloudinary.com/)
12
+ - **Email**: [Resend](https://resend.com/)
13
+ - **Analytics**: Google Analytics (via `@next/third-parties`)
14
+ - **Forms**: React Hook Form + Zod validation
15
+ - **UI Components**: Lucide React, React Icons, Framer Motion
16
+ - **TypeScript**: Full type safety
17
+
18
+ ## ✨ Features
19
+
20
+ - ⚡️ **Turbopack** for ultra-fast dev & build
21
+ - 🎨 **Modern UI** with Tailwind CSS 4 and premium animations
22
+ - 📱 **Fully Responsive** design
23
+ - 🔐 **Supabase Integration** for database and authentication
24
+ - 🖼️ **Cloudinary Integration** for media optimization
25
+ - 📬 **Email Service** with Resend
26
+ - 🔍 **SEO Optimized** (metadata, sitemap, robots.txt, Schema.org)
27
+ - 📊 **Google Analytics** integration
28
+ - 🗂️ **Service Layer Architecture** for clean code organization
29
+ - 🎯 **Redux Store** with TypeScript support
30
+ - ✅ **Form Validation** with React Hook Form & Zod
31
+ - 🌐 **Multi-language Ready** structure
32
+
33
+ ## 🚀 Quick Start
34
+
35
+ ### Prerequisites
36
+
37
+ - Node.js 20+ and npm installed
38
+ - Supabase account (free tier available)
39
+ - Cloudinary account (free tier available)
40
+ - Resend account (free tier available)
41
+
42
+ ### Installation
43
+
44
+ 1. **Copy this template to your new project:**
45
+
46
+ ```bash
47
+ cp -r /path/to/nextjs-template /path/to/your-new-project
48
+ cd /path/to/your-new-project
49
+ ```
50
+
51
+ 2. **Install dependencies:**
52
+
53
+ ```bash
54
+ npm install
55
+ ```
56
+
57
+ 3. **Set up environment variables:**
58
+
59
+ ```bash
60
+ cp .env.example .env
61
+ ```
62
+
63
+ Then fill in your actual values in `.env`
64
+
65
+ 4. **Run development server:**
66
+
67
+ ```bash
68
+ npm run dev
69
+ ```
70
+
71
+ 5. **Open [http://localhost:3000](http://localhost:3000)**
72
+
73
+ ## 📁 Project Structure
74
+
75
+ ```
76
+ nextjs-template/
77
+ ├── public/ # Static assets
78
+ ├── src/
79
+ │ ├── app/ # Next.js App Router pages
80
+ │ │ ├── layout.tsx # Root layout with metadata
81
+ │ │ ├── page.tsx # Home page
82
+ │ │ ├── robots.ts # Robots.txt generation
83
+ │ │ └── sitemap.ts # Sitemap generation
84
+ │ ├── components/ # Reusable UI components
85
+ │ ├── data/ # Static data and types
86
+ │ ├── hooks/ # Custom React hooks
87
+ │ ├── lib/ # Utilities and services
88
+ │ │ ├── providers/ # Context providers (Redux, etc.)
89
+ │ │ ├── seo/ # SEO utilities
90
+ │ │ ├── services/ # Service layer (API calls)
91
+ │ │ ├── supabase/ # Supabase client & utilities
92
+ │ │ └── utils/ # Helper functions
93
+ │ └── store/ # Redux store
94
+ │ ├── actions/ # Redux actions
95
+ │ ├── reducers/ # Redux reducers
96
+ │ └── types/ # Redux types
97
+ ├── .env.example # Environment variables template
98
+ ├── package.json # Dependencies
99
+ └── tsconfig.json # TypeScript config
100
+ ```
101
+
102
+ ## 📜 Available Scripts
103
+
104
+ ```bash
105
+ # Development with Turbopack
106
+ npm run dev
107
+
108
+ # Production build
109
+ npm run build
110
+
111
+ # Start production server
112
+ npm start
113
+
114
+ # Lint code
115
+ npm run lint
116
+ ```
117
+
118
+ ## 🚀 Deployment
119
+
120
+ ### Vercel (Recommended)
121
+
122
+ 1. Push code to GitHub
123
+ 2. Import project in [Vercel](https://vercel.com)
124
+ 3. Add environment variables
125
+ 4. Deploy!
126
+
127
+ ---
128
+
129
+ **Happy coding! 🎉**
@@ -0,0 +1,22 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": true,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "src/app/globals.css",
9
+ "baseColor": "zinc",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "aliases": {
15
+ "components": "@/components",
16
+ "utils": "@/lib/utils",
17
+ "ui": "@/components/ui",
18
+ "lib": "@/lib",
19
+ "hooks": "@/hooks"
20
+ },
21
+ "registries": {}
22
+ }
@@ -0,0 +1,25 @@
1
+ import { dirname } from "path";
2
+ import { fileURLToPath } from "url";
3
+ import { FlatCompat } from "@eslint/eslintrc";
4
+
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+
8
+ const compat = new FlatCompat({
9
+ baseDirectory: __dirname,
10
+ });
11
+
12
+ const eslintConfig = [
13
+ ...compat.extends("next/core-web-vitals", "next/typescript"),
14
+ {
15
+ ignores: [
16
+ "node_modules/**",
17
+ ".next/**",
18
+ "out/**",
19
+ "build/**",
20
+ "next-env.d.ts",
21
+ ],
22
+ },
23
+ ];
24
+
25
+ export default eslintConfig;
@@ -0,0 +1,25 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ images: {
5
+ formats: ['image/avif', 'image/webp'],
6
+ deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
7
+ imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
8
+ remotePatterns: [
9
+ {
10
+ protocol: 'https',
11
+ hostname: 'images.ctfassets.net',
12
+ },
13
+ {
14
+ protocol: 'https',
15
+ hostname: 'assets.ctfassets.net',
16
+ },
17
+ {
18
+ protocol: 'https',
19
+ hostname: 'res.cloudinary.com',
20
+ },
21
+ ],
22
+ },
23
+ };
24
+
25
+ export default nextConfig;