{"id":34827382,"url":"https://github.com/profullstack/coldfollow-web","last_synced_at":"2026-05-22T22:36:29.313Z","repository":{"id":291416090,"uuid":"977552697","full_name":"profullstack/coldfollow-web","owner":"profullstack","description":null,"archived":false,"fork":false,"pushed_at":"2025-07-01T00:22:26.000Z","size":2468,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-12-27T00:52:39.882Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/profullstack.png","metadata":{"files":{"readme":"README-adding-routes.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-04T13:22:31.000Z","updated_at":"2025-07-01T00:22:29.000Z","dependencies_parsed_at":"2025-06-29T23:35:04.620Z","dependency_job_id":null,"html_url":"https://github.com/profullstack/coldfollow-web","commit_stats":null,"previous_names":["profullstack/coldfollow-web"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/profullstack/coldfollow-web","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profullstack%2Fcoldfollow-web","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profullstack%2Fcoldfollow-web/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profullstack%2Fcoldfollow-web/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profullstack%2Fcoldfollow-web/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/profullstack","download_url":"https://codeload.github.com/profullstack/coldfollow-web/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/profullstack%2Fcoldfollow-web/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33374440,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-22T21:56:13.512Z","status":"ssl_error","status_checked_at":"2026-05-22T21:56:10.769Z","response_time":265,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-25T15:20:52.346Z","updated_at":"2026-05-22T22:36:29.301Z","avatar_url":"https://github.com/profullstack.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Adding a New Route/Page/Component\n\nThis guide explains how to add a new route, page, or component to the application using our router setup.\n\n## Overview\n\nOur application uses a Single Page Application (SPA) router with helper utilities that simplify adding and managing routes. The router handles page transitions, authentication checks, and subscription requirements with minimal code.\n\n## Step-by-Step Guide\n\n### 1. Create the HTML View File\n\nFirst, create an HTML file for your new page in the `/views` directory:\n\n```html\n\u003c!-- /views/my-new-feature.html --\u003e\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n  \u003ctitle\u003eMy New Feature\u003c/title\u003e\n  \u003clink rel=\"stylesheet\" href=\"/css/main.css\"\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003cdiv class=\"my-feature-container\"\u003e\n    \u003ch1 data-i18n=\"my_feature.title\"\u003eMy New Feature\u003c/h1\u003e\n    \u003cp data-i18n=\"my_feature.description\"\u003eThis is my new feature page.\u003c/p\u003e\n    \n    \u003c!-- Your page content here --\u003e\n    \u003cdiv class=\"feature-content\"\u003e\n      \u003cform id=\"my-feature-form\"\u003e\n        \u003c!-- Form fields --\u003e\n        \u003cbutton type=\"submit\" data-i18n=\"my_feature.submit\"\u003eSubmit\u003c/button\u003e\n      \u003c/form\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n### 2. Create an Initializer Function (Optional)\n\nIf your page needs JavaScript initialization (event listeners, data loading, etc.), create an initializer function in `page-initializers.js`:\n\n```javascript\n/**\n * Initialize the new feature page\n */\nexport function initMyNewFeaturePage() {\n  console.log('Initializing my new feature page');\n  \n  // Get elements\n  const form = document.getElementById('my-feature-form');\n  if (!form) {\n    console.error('My feature form not found');\n    return;\n  }\n  \n  // Add event listeners\n  form.addEventListener('submit', async (e) =\u003e {\n    e.preventDefault();\n    \n    // Form submission logic\n    console.log('Form submitted');\n    \n    // Get form data\n    const formData = new FormData(form);\n    const formDataObj = Object.fromEntries(formData.entries());\n    \n    // Process the form data\n    console.log('Form data:', formDataObj);\n    \n    // Additional logic...\n  });\n  \n  // Other initialization code...\n}\n```\n\nDon't forget to export the initializer function at the top of the file:\n\n```javascript\nexport {\n  // ... existing exports\n  initMyNewFeaturePage\n} from './page-initializers.js';\n```\n\n### 3. Add the Route to the Router\n\n#### Approach 1: Add Directly to router.js\n\nOpen `router.js` and add your new route to the `createRoutes` call in the `defineRoutes` function:\n\n```javascript\n// In router.js\nexport function defineRoutes(router) {\n  console.log('Defining routes...');\n  \n  // Define routes using the createRoutes helper\n  const routes = createRoutes({\n    // Existing routes...\n    '/': '/views/home.html',\n    \n    // Add your new route\n    '/my-new-feature': {\n      viewPath: '/views/my-new-feature.html',\n      afterRender: initMyNewFeaturePage, // Optional\n      requireAuth: true  // If the route requires authentication\n    }\n  });\n  \n  // Rest of the function...\n}\n```\n\n#### Approach 2: Create a Separate Routes File\n\nFor better organization in larger applications, you can create a separate file for related routes:\n\n```javascript\n// feature-routes.js\nimport { createRoutes } from './route-helpers.js';\nimport { initMyNewFeaturePage } from './page-initializers.js';\n\nexport const featureRoutes = createRoutes({\n  '/my-new-feature': {\n    viewPath: '/views/my-new-feature.html',\n    afterRender: initMyNewFeaturePage,\n    requireAuth: true\n  },\n  '/my-new-feature/settings': {\n    viewPath: '/views/my-new-feature-settings.html',\n    requireAuth: true\n  }\n});\n```\n\nThen import and merge these routes in `router.js`:\n\n```javascript\n// In router.js\nimport { featureRoutes } from './feature-routes.js';\n\nexport function defineRoutes(router) {\n  console.log('Defining routes...');\n  \n  // Define core routes\n  const coreRoutes = createRoutes({\n    // Existing routes...\n  });\n  \n  // Merge all routes\n  const routes = {\n    ...coreRoutes,\n    ...featureRoutes\n    // Add more route collections as needed\n  };\n  \n  // Register routes with the router\n  router.registerRoutes(routes);\n  \n  // Rest of the function...\n}\n```\n\n## Route Configuration Options\n\nWhen adding a route, you can use these options:\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `viewPath` | String | Path to the HTML view file |\n| `afterRender` | Function | Function to run after the page is rendered |\n| `beforeEnter` | Function | Function to run before entering the route |\n| `requireAuth` | Boolean | Whether the route requires authentication |\n| `requireSubscription` | Boolean | Whether the route requires an active subscription |\n\n## Examples\n\n### Basic Route\n\n```javascript\n'/about': '/views/about.html'\n```\n\n### Route with Initialization\n\n```javascript\n'/profile': {\n  viewPath: '/views/profile.html',\n  afterRender: initProfilePage\n}\n```\n\n### Protected Route (Requires Authentication)\n\n```javascript\n'/dashboard': {\n  viewPath: '/views/dashboard.html',\n  requireAuth: true\n}\n```\n\n### Premium Route (Requires Subscription)\n\n```javascript\n'/premium-feature': {\n  viewPath: '/views/premium-feature.html',\n  requireSubscription: true\n}\n```\n\n### Route with Custom Guard\n\n```javascript\n'/admin': {\n  viewPath: '/views/admin.html',\n  beforeEnter: (to, from, next) =\u003e {\n    const userRole = localStorage.getItem('user_role');\n    if (userRole === 'admin') {\n      next();\n    } else {\n      next('/access-denied');\n    }\n  }\n}\n```\n\n## Testing Your New Route\n\nAfter adding the route, you can test it by navigating to the URL in your browser:\n\n```\nhttp://localhost:3000/my-new-feature\n```\n\nThe router will handle loading the HTML, running the initializer function, and checking authentication if required.\n\n## Best Practices\n\n1. **Organize Related Routes**: Keep related routes together, either in the same section of `router.js` or in a separate routes file.\n\n2. **Use Descriptive Route Names**: Choose route paths that clearly describe the feature or page.\n\n3. **Follow Naming Conventions**: Use consistent naming for HTML files, initializer functions, and route paths.\n\n4. **Handle Authentication Properly**: Use the `requireAuth` option for protected routes instead of implementing custom checks.\n\n5. **Add Internationalization**: Use `data-i18n` attributes for text that needs to be translated.\n\n6. **Clean Up Event Listeners**: If your initializer adds event listeners, make sure to remove them when the page is unloaded to prevent memory leaks.\n\n7. **Test Thoroughly**: Test your new route with different scenarios (logged in, logged out, with/without subscription) to ensure it behaves correctly.\n\n## Using the Generator Script\n\nThe generator script provides tools for creating various components for both client-side and server-side development.\n\n### Prerequisites\n\nMake sure the script is executable:\n\n```bash\nchmod +x bin/generator.js\n```\n\n### Command Structure\n\nThe generator now uses a category-based command structure:\n\n```bash\n./bin/generator.js \u003ccategory\u003e \u003ccommand\u003e [options]\n```\n\nCategories:\n- `client`: Client-side generators\n- `server`: Server-side generators\n\n### Client-Side Commands\n\n#### Generate a Client Route\n\n```bash\n./bin/generator.js client route --route=\"/my-feature\" --name=\"My Feature\" [--auth] [--subscription]\n```\n\nOptions:\n- `--route`: The route path (required, e.g., \"/my-feature\")\n- `--name`: The feature name (required, e.g., \"My Feature\")\n- `--auth`: Add this flag if the route requires authentication\n- `--subscription`: Add this flag if the route requires an active subscription\n\nExample:\n```bash\n./bin/generator.js client route --route=\"/contact-us\" --name=\"Contact Us\"\n```\n\nThis will:\n1. Create a new HTML view file at `public/views/contact-us.html`\n2. Add an initializer function `initContactUsPage` to `public/js/page-initializers.js`\n3. Add the route to `public/js/router.js`\n\n### Server-Side Commands\n\n#### Generate a Server Route\n\n```bash\n./bin/generator.js server route --path=\"/api/v1/users\" --controller=\"UserController\" --method=\"get\"\n```\n\nOptions:\n- `--path`: The API path (required, e.g., \"/api/v1/users\")\n- `--controller`: The controller name (required, e.g., \"UserController\")\n- `--method`: The HTTP method (required, e.g., \"get\", \"post\", \"put\", \"delete\", \"patch\")\n\nExample:\n```bash\n./bin/generator.js server route --path=\"/api/v1/users\" --controller=\"User\" --method=\"get\"\n```\n\nThis will add a new route to the appropriate route file in the `src/routes` directory.\n\n#### Generate a Database Migration\n\n```bash\n./bin/generator.js server migration --name=\"add_user_fields\"\n```\n\nOptions:\n- `--name`: The migration name (required, e.g., \"add_user_fields\")\n\nExample:\n```bash\n./bin/generator.js server migration --name=\"add_user_profile_fields\"\n```\n\nThis will create a timestamped SQL migration file in the `supabase/migrations` directory. The migration file includes clearly separated sections for \"up\" migrations (changes to apply) and \"down\" migrations (how to revert the changes).\n\n#### Generate a Controller\n\n```bash\n./bin/generator.js server controller --name=\"UserController\"\n```\n\nOptions:\n- `--name`: The controller name (required, e.g., \"UserController\" or \"User\")\n\nExample:\n```bash\n./bin/generator.js server controller --name=\"User\"\n```\n\nThis will create a new controller file with standard CRUD methods in the `src/controllers` directory.\n\n### Backward Compatibility\n\nFor backward compatibility, the old command format is still supported but will show a deprecation warning:\n\n```bash\n./bin/generator.js route --route=\"/my-feature\" --name=\"My Feature\"  # Deprecated\n```\n\n### Getting Help\n\nFor general help:\n```bash\n./bin/generator.js --help\n```\n\nFor command-specific help:\n```bash\n./bin/generator.js client route --help\n./bin/generator.js server route --help\n./bin/generator.js server migration --help\n./bin/generator.js server controller --help\n```\n\nAfter running the generator, you can customize the generated files to fit your specific requirements.\n\n## Template-Based Generation\n\nThe generator script uses a template-based approach for creating files. Templates are stored in the `templates` directory and are organized by category and type:\n\n```\ntemplates/\n├── client/\n│   └── route/\n│       ├── view.html.template\n│       ├── view.js.template\n│       └── initializer.js.template\n└── server/\n    ├── controller.js.template\n    ├── route.js.template\n    └── migration.sql.template\n```\n\n### Benefits of Template-Based Generation\n\n1. **Separation of Concerns**: Templates are separate from the generator code, making maintenance easier\n2. **Consistency**: All generated files follow the same structure and style\n3. **Customization**: Templates can be modified without changing the generator code\n4. **Flexibility**: New templates can be added for additional file types\n\n### Customizing Templates\n\nIf you need to modify the structure or content of generated files, you can edit the templates directly. Templates use placeholders like `{{kebabCase}}`, `{{featureName}}`, and `{{controllerName}}` that are replaced with actual values during generation.\n\nFor example, to change the structure of generated HTML views, edit `templates/client/route/view.html.template`.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprofullstack%2Fcoldfollow-web","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprofullstack%2Fcoldfollow-web","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprofullstack%2Fcoldfollow-web/lists"}