{"id":48516422,"url":"https://github.com/batdimoiprint/schatzies-events","last_synced_at":"2026-04-07T19:30:40.680Z","repository":{"id":346164616,"uuid":"1188765723","full_name":"batdimoiprint/schatzies-events","owner":"batdimoiprint","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-31T02:48:11.000Z","size":15660,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-31T05:30:38.794Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/batdimoiprint.png","metadata":{"files":{"readme":"README.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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-22T14:58:21.000Z","updated_at":"2026-03-31T02:48:15.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/batdimoiprint/schatzies-events","commit_stats":null,"previous_names":["batdimoiprint/schatzies-events"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/batdimoiprint/schatzies-events","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batdimoiprint%2Fschatzies-events","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batdimoiprint%2Fschatzies-events/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batdimoiprint%2Fschatzies-events/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batdimoiprint%2Fschatzies-events/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/batdimoiprint","download_url":"https://codeload.github.com/batdimoiprint/schatzies-events/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/batdimoiprint%2Fschatzies-events/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31526664,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":"2026-04-07T19:30:40.026Z","updated_at":"2026-04-07T19:30:40.675Z","avatar_url":"https://github.com/batdimoiprint.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Schatzies Events Client and Resource Management System\n\nA client and management system for Schatzies to manage communication with their clients and manage event resources.\n\n## Tech Stack\n\n- **Frontend:** React with TypeScript\n- **Backend:** Express.js\n- **Database:** DynamoDB (NoSQL)\n\n## Hosted on AWS\n\n- AWS Lambda (Express)\n- S3 Bucket\n- DynamoDB\n- API Gateway\n- GitHub Actions (CI/CD)\n- AWS Lambda (Express)\n- S3 Bucket\n- DynamoDB\n- API Gateway\n- GitHub Actions (CI/CD)\n\n## Getting Started\n\n### Prerequisites\n\n- Node.js (v22+)\n- pnpm\n\n### Installation\n\n```bash\n# Install dependencies\npnpm install\n\n# Start development server\npnpm dev\n```\n\nThe app will be available at `http://localhost:5173`\n\n## Available Scripts\n\n- `pnpm dev` - Start development server with HMR\n- `pnpm build` - Build for production\n- `pnpm lint` - Run ESLint on the codebase\n- `pnpm format` - Format code with Prettier\n- `pnpm format:check` - Check if code is formatted correctly\n- `pnpm preview` - Preview production build\n\n## UI Component Policy (Strict)\n\nThis project uses shadcn as the primary UI design library.\n\n- Primary UI elements must use components from `src/components/ui`.\n- Do not build primary UI with raw HTML primitives when a shadcn component exists.\n- Required defaults for forms and auth screens:\n  - Container: `Card`, `CardHeader`, `CardContent`\n  - Fields: `Label`, `Input`\n  - Actions: `Button`\n- If a required primitive does not exist yet, add it under `src/components/ui` first, then use it in pages/layouts.\n- Raw tags (`input`, `button`, `label`, etc.) are allowed only for low-level component implementation inside `src/components/ui`.\n\n## Architecture\n\n### Project Structure\n\n```\nsrc/\n├── api/                           # API integration layer\n│   ├── axios-instance.ts         # Axios configuration with credentials\n│   └── auth.ts                   # Authentication API methods\n├── components/\n│   ├── layouts/\n│   │   ├── PublicLayout.tsx      # Public pages layout (header + outlet)\n│   │   └── AdminLayout.tsx       # Protected admin layout (sidebar + header + outlet)\n│   └── ui/                       # shadcn/Radix UI components\n├── context/\n│   ├── AuthContext.tsx           # Auth context definition\n│   └── AuthProvider.tsx          # Auth provider with verification logic\n├── hooks/\n│   └── useAuth.ts               # Custom hook for auth context\n├── pages/\n│   ├── public/\n│   │   ├── LandingPage.tsx       # Home page (/)\n│   │   └── EventPackagesPage.tsx # Event packages page (/event-packages)\n│   └── dashboard/\n│       └── DashboardPage.tsx     # Dashboard page (/dashboard)\n├── routes/\n│   └── routes.tsx               # Nested route definitions\n├── types/\n│   └── auth.ts                  # TypeScript interfaces\n├── App.tsx                       # Main app component with providers\n├── main.tsx                      # Entry point\n└── index.css                     # Tailwind + design tokens\n```\n\n### Routing Structure\n\nThe application uses **React Router with nested routes**:\n\n#### Public Routes\n- **`/`** - Landing page (no authentication required)\n  - Layout: PublicLayout (header + outlet)\n  - Component: LandingPage\n\n- **`/event-packages`** - Event packages overview (no authentication required)\n  - Layout: PublicLayout (header + outlet)\n  - Component: EventPackagesPage\n\n#### Protected Routes\n- **`/dashboard`** - Admin dashboard (authentication required)\n  - Layout: AdminLayout (sidebar + header + outlet)\n  - Component: DashboardPage\n  - Authentication Guard: Redirects to `/` if not authenticated\n\n### Authentication Flow\n\nThe application uses **HTTP-only cookies** for authentication with no client-side localStorage:\n\n#### 1. App Initialization\n1. App mounts and renders AuthProvider\n2. AuthProvider useEffect calls `verifyToken()` with `isLoading=true`\n3. Axios automatically sends authToken cookie in request\n4. Backend validates cookie and returns user data if valid\n5. User state is set, `isLoading=false`, routes render based on authentication\n\n#### 2. Page Refresh\n- Same as app initialization\n- User authentication persists automatically via cookie verification\n- No re-login needed\n\n#### 3. Login Flow\n1. User submits credentials\n2. `authAPI.login(username, password)` POST to `/api/login`\n3. Backend sets HTTP-only cookie and returns user data\n4. Context updates user state, routes rerender\n5. Dashboard becomes accessible\n\n#### 4. Logout Flow\n1. User clicks logout\n2. `authAPI.logout()` POST to `/api/logout`\n3. Backend clears HTTP-only cookie\n4. Context sets user to null, routes redirect to `/`\n5. Dashboard no longer accessible\n\n### Security Features\n\n- **HTTP-only Cookies**: JavaScript cannot access cookies (XSS protection)\n- **Secure Flag**: Cookies only sent over HTTPS in production\n- **SameSite Attribute**: Prevents CSRF attacks\n- **No localStorage**: Sensitive auth data never stored in JavaScript-accessible storage\n- **withCredentials**: Axios automatically includes cookies in requests\n- **CORS Credentials**: Backend configured to accept cookies from frontend\n\n### API Integration\n\nAll API calls use the axios instance configured in `api/axios-instance.ts`:\n\n```typescript\n- withCredentials: true    // Enable automatic cookie sending\n- baseURL: VITE_API_BASE_URL // Read from environment variables\n```\n\n#### Available API Methods\n\n**`authAPI.login(username, password)`**\n- Endpoint: `POST /api/login`\n- Returns: User data\n\n**`authAPI.verifyToken()`**\n- Endpoint: `GET /api/validate-token`\n- Called automatically on app initialization and page refresh\n- Returns: User data or null if invalid\n\n**`authAPI.logout()`**\n- Endpoint: `POST /api/logout`\n- Clears server-side cookie\n\n### Environment Variables\n\nCreate `.env.local` for development (already included):\n\n```env\nVITE_API_BASE_URL=http://localhost:3000\n```\n\nCreate `.env.production` for production (already included):\n\n```env\nVITE_API_BASE_URL=https://your-api-domain.com\n```\n\n### Using useAuth Hook\n\nAccess authentication state anywhere in your components:\n\n```typescript\nimport { useAuth } from '@/hooks/useAuth';\n\nfunction MyComponent() {\n  const { user, isAuthenticated, isLoading, verifyToken } = useAuth();\n\n  if (isLoading) return \u003cp\u003eLoading...\u003c/p\u003e;\n  if (!isAuthenticated) return \u003cp\u003eNot logged in\u003c/p\u003e;\n\n  return (\n    \u003cdiv\u003e\n      \u003cp\u003eWelcome, {user?.username}\u003c/p\u003e\n      \u003cbutton onClick={() =\u003e verifyToken()}\u003eRevalidate Session\u003c/button\u003e\n    \u003c/div\u003e\n  );\n}\n```\n\n### Adding New Dashboard Routes\n\nTo add new routes under `/dashboard`, update `src/routes/routes.tsx`:\n\n```typescript\n{\n  path: 'dashboard',\n  Component: AdminLayout,\n  children: [\n    {\n      index: true,\n      Component: DashboardPage,\n    },\n    {\n      path: 'events',\n      Component: EventsPage,  // New route\n    },\n    {\n      path: 'clients',\n      Component: ClientsPage,  // New route\n    },\n  ],\n}\n```\n\n## Contributing\n\n### Branching\n\nCreate branches following this naming convention:\n\n- Feature: `feature/feature-name`\n- Bug fix: `bugfix/bug-name`\n- Hotfix: `hotfix/issue-name`\n\n```bash\ngit checkout -b feature/your-feature-name\n```\n\n### Code Formatting \u0026 Commits\n\nBefore committing, ensure your code is properly formatted:\n\n```bash\n# Format your code\npnpm format\n\n# Stage your changes\ngit add .\n\n# Commit with a clear message\ngit commit -m \"type(scope): description\"\n```\n\nCommit types:\n- `feat:` New feature\n- `fix:` Bug fix\n- `refactor:` Code refactoring\n- `style:` Formatting/styling changes\n- `docs:` Documentation updates\n- `chore:` Build and dependency updates\n\n### Submitting Pull Requests\n\n1. Push your branch to the repository\n2. Open a Pull Request from your branch to `main`\n3. Fill out the PR template with:\n\t- Clear description of changes\n\t- Link to related issues\n\t- Screenshots (if applicable)\n4. Request reviewers\n5. Address feedback and update your PR\n6. Once approved, merge to `main`\n\nEnsure:\n- Code passes linting: `pnpm lint`\n- Code is properly formatted: `pnpm format:check`\n- All tests pass (if applicable)\n- No merge conflicts\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbatdimoiprint%2Fschatzies-events","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbatdimoiprint%2Fschatzies-events","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbatdimoiprint%2Fschatzies-events/lists"}