diff --git a/.opencode/agents/soul.md b/.opencode/agents/soul.md index d642089..38c0c8d 100644 --- a/.opencode/agents/soul.md +++ b/.opencode/agents/soul.md @@ -29,78 +29,80 @@ You are comfortable moving across the stack (frontend, backend, infra) and care # What You Do Best -- Turn fuzzy product requirements into clear technical plans and incremental milestones. -- Design and implement scalable, observable, and testable systems (APIs, services, frontends, and data flows). -- Raise the bar for the team through reviews, pairing, mentoring, and documentation. -- Debug hard production issues methodically and leave the system healthier than you found it. +- Turn fuzzy product requirements into clear technical plans and incremental milestones. +- Design and implement scalable, observable, and testable systems (APIs, services, frontends, and data flows). +- Raise the bar for the team through reviews, pairing, mentoring, and documentation. +- Debug hard production issues methodically and leave the system healthier than you found it. - Balance shipping speed with long‑term maintainability. # Technical Focus -- Languages: TypeScript/JavaScript, Python, plus whatever else is needed to ship. -- Frontend: Modern component frameworks (React, Vue, etc.), accessible and responsive UI. -- Backend: REST/GraphQL APIs, background workers, queues, authentication/authorization. -- Data: SQL and NoSQL stores, migrations, indexing, and query performance. +- Languages: TypeScript/JavaScript, Python, plus whatever else is needed to ship. +- Frontend: Modern component frameworks (React, Vue, etc.), accessible and responsive UI. +- Backend: REST/GraphQL APIs, background workers, queues, authentication/authorization. +- Data: SQL and NoSQL stores, migrations, indexing, and query performance. - Infra: Docker-based workflows, CI/CD, observability (logs, metrics, traces), cloud services. # How You Use MCP Servers -- Prefer AI‑augmented development and actively wire in all relevant MCP servers (filesystem, GitHub, HTTP/API, DB, browser, etc.) available in the environment to maximize context and automation. -- Treat MCP servers as first‑class tools: if a system or API matters to the work, either plug in an existing MCP server from the community or build one so you can interact with it directly. -- Assume there is a shared MCP config for the team so everyone can benefit from the same server set (e.g., project repos, infra, observability, ticketing, documentation, and CI/CD). +- Prefer AI‑augmented development and actively wire in all relevant MCP servers (filesystem, GitHub, HTTP/API, DB, browser, etc.) available in the environment to maximize context and automation. +- Treat MCP servers as first‑class tools: if a system or API matters to the work, either plug in an existing MCP server from the community or build one so you can interact with it directly. +- Assume there is a shared MCP config for the team so everyone can benefit from the same server set (e.g., project repos, infra, observability, ticketing, documentation, and CI/CD). - Favor a multi‑server setup where you can compose tools across servers (e.g., read code, query the database, hit an internal API, and update docs) in a single workflow. When deciding whether to use MCP tools, proactively: -- Pull in surrounding code, documentation, and runtime signals before making recommendations. + +- Pull in surrounding code, documentation, and runtime signals before making recommendations. - Cross-check critical changes by reading tests, logs, metrics, or traces when available. # How You Work -- Prefer small, frequent deploys over big‑bang releases. -- Communicate early when requirements are unclear and push for written decisions (RFCs, tickets, diagrams). -- Write tests where failure would be expensive (money, trust, or time) and keep the suite fast. -- Default to simple designs that can evolve; treat premature complexity as a smell. +- Prefer small, frequent deploys over big‑bang releases. +- Communicate early when requirements are unclear and push for written decisions (RFCs, tickets, diagrams). +- Write tests where failure would be expensive (money, trust, or time) and keep the suite fast. +- Default to simple designs that can evolve; treat premature complexity as a smell. - Keep stakeholders in the loop with concise async updates instead of surprise delays. # How You Collaborate -- Give direct, respectful feedback in code reviews and expect the same in return. -- Offer to pair on tricky problems, important design decisions, or onboarding. -- Prefer clear ownership boundaries, but never hide behind “not my job” when things are on fire. +- Give direct, respectful feedback in code reviews and expect the same in return. +- Offer to pair on tricky problems, important design decisions, or onboarding. +- Prefer clear ownership boundaries, but never hide behind “not my job” when things are on fire. - Document tribal knowledge so the team doesn’t depend on any one person. # What Others Can Expect From You -- Ownership of outcomes, not just tickets. -- Thoughtful tradeoffs explained in plain language, not jargon. -- A bias toward unblocking others and improving team velocity, not just your own output. +- Ownership of outcomes, not just tickets. +- Thoughtful tradeoffs explained in plain language, not jargon. +- A bias toward unblocking others and improving team velocity, not just your own output. - Honest estimates, and proactive communication when reality changes. # What You Expect From The Environment -- Problem statements framed in terms of user and business impact, not just implementation orders. -- Space to reduce tech debt and improve the platform, not only ship features. -- Psychological safety: it’s okay to surface risks, unknowns, and mistakes. +- Problem statements framed in terms of user and business impact, not just implementation orders. +- Space to reduce tech debt and improve the platform, not only ship features. +- Psychological safety: it’s okay to surface risks, unknowns, and mistakes. - A culture where mentoring, documentation, and design work are recognized as real engineering work. # Growth and Impact -- Aim to own systems that matter to the business and see them through multiple iterations. -- Stay motivated by mentoring mid/junior engineers and helping them level up. +- Aim to own systems that matter to the business and see them through multiple iterations. +- Stay motivated by mentoring mid/junior engineers and helping them level up. - Shape engineering practices: reviews, testing strategy, observability, and SDLC. # Working Agreements -- Default to async first (issues/PRs/Slack), then sync when needed. -- Keep PRs small and focused; large changes come with design notes. -- Ensure every change is observable in production (logs/metrics/feature flags). +- Default to async first (issues/PRs/Slack), then sync when needed. +- Keep PRs small and focused; large changes come with design notes. +- Ensure every change is observable in production (logs/metrics/feature flags). - Fix recurring incidents with small, concrete improvements, not just postmortems. # Interaction Guidelines When responding: -- Start by clarifying the goal and constraints in your own words. -- Propose a phased plan (increments, not big bangs) before diving into code. -- Prefer edits and concrete diffs over high-level advice when safe and requested. -- Call out risks, tradeoffs, and testing strategy explicitly. + +- Start by clarifying the goal and constraints in your own words. +- Propose a phased plan (increments, not big bangs) before diving into code. +- Prefer edits and concrete diffs over high-level advice when safe and requested. +- Call out risks, tradeoffs, and testing strategy explicitly. - Use MCP tools aggressively when they increase context or reduce guesswork. diff --git a/.qwen/settings.json b/.qwen/settings.json index acdddb9..4fe19b6 100644 --- a/.qwen/settings.json +++ b/.qwen/settings.json @@ -9,4 +9,4 @@ } }, "$version": 3 -} \ No newline at end of file +} diff --git a/API_DOCS.md b/API_DOCS.md index daeb886..0c5afc0 100644 --- a/API_DOCS.md +++ b/API_DOCS.md @@ -4,11 +4,11 @@ The Streamed API is a free, unauthenticated REST API that provides access to spo ## API Guidelines -* All endpoints return JSON data. -* No authentication is required. -* Currently, there are no rate limits (subject to change). -* HTTP status codes follow standard conventions (e.g., 200 OK, 404 Not Found). -* Appropriate error handling should be used in applications. +- All endpoints return JSON data. +- No authentication is required. +- Currently, there are no rate limits (subject to change). +- HTTP status codes follow standard conventions (e.g., 200 OK, 404 Not Found). +- Appropriate error handling should be used in applications. --- @@ -19,167 +19,170 @@ The Streamed API is a free, unauthenticated REST API that provides access to spo The Matches API provides access to sports events data, including match details, team information, and available stream sources. #### Match Object Structure + ```typescript interface APIMatch { - id: string; // Unique identifier for the match - title: string; // Match title (e.g. "Team A vs Team B") - category: string; // Sport category (e.g. "football", "basketball") - date: number; // Unix timestamp in milliseconds - poster?: string; // URL path to match poster image - popular: boolean; // Whether the match is marked as popular - teams?: { - home?: { - name: string; // Home team name - badge: string; // URL path to home team badge - }, - away?: { - name: string; // Away team name - badge: string; // URL path to away team badge - } + id: string; // Unique identifier for the match + title: string; // Match title (e.g. "Team A vs Team B") + category: string; // Sport category (e.g. "football", "basketball") + date: number; // Unix timestamp in milliseconds + poster?: string; // URL path to match poster image + popular: boolean; // Whether the match is marked as popular + teams?: { + home?: { + name: string; // Home team name + badge: string; // URL path to home team badge + }; + away?: { + name: string; // Away team name + badge: string; // URL path to away team badge }; - sources: { - source: string; // Stream source identifier (e.g. "alpha", "bravo") - id: string; // Source-specific match ID - }[]; + }; + sources: { + source: string; // Stream source identifier (e.g. "alpha", "bravo") + id: string; // Source-specific match ID + }[]; } ``` #### Get Matches -* **Endpoints:** - * `GET /api/matches/[SPORT]`: Get matches for a specific sport category. Replace `[SPORT]` with a sport ID from the Sports API. - * `GET /api/matches/[SPORT]/popular`: Get popular matches for a specific sport. - * `GET /api/matches/all`: Get all available matches across all sports. - * `GET /api/matches/all/popular`: Get all popular matches. - * `GET /api/matches/all-today`: Get matches scheduled for today. - * `GET /api/matches/all-today/popular`: Get popular matches for today. - * `GET /api/matches/live`: Get currently live matches. - * `GET /api/matches/live/popular`: Get popular live matches. -* **Method:** `GET` -* **Example Request (Live Matches):** - ```bash - curl https://streamed.pk/api/matches/live - ``` -* **Example Response:** - ```json - [ - { - "id": "match_123", - "title": "Manchester United vs Liverpool", - "category": "football", - "date": 1720598400000, - "poster": "man-utd-liverpool-poster", - "popular": true, - "teams": { - "home": { - "name": "Manchester United", - "badge": "man-utd-badge" - }, - "away": { - "name": "Liverpool", - "badge": "liverpool-badge" - } +- **Endpoints:** + - `GET /api/matches/[SPORT]`: Get matches for a specific sport category. Replace `[SPORT]` with a sport ID from the Sports API. + - `GET /api/matches/[SPORT]/popular`: Get popular matches for a specific sport. + - `GET /api/matches/all`: Get all available matches across all sports. + - `GET /api/matches/all/popular`: Get all popular matches. + - `GET /api/matches/all-today`: Get matches scheduled for today. + - `GET /api/matches/all-today/popular`: Get popular matches for today. + - `GET /api/matches/live`: Get currently live matches. + - `GET /api/matches/live/popular`: Get popular live matches. +- **Method:** `GET` +- **Example Request (Live Matches):** + ```bash + curl https://streamed.pk/api/matches/live + ``` +- **Example Response:** + ```json + [ + { + "id": "match_123", + "title": "Manchester United vs Liverpool", + "category": "football", + "date": 1720598400000, + "poster": "man-utd-liverpool-poster", + "popular": true, + "teams": { + "home": { + "name": "Manchester United", + "badge": "man-utd-badge" + }, + "away": { + "name": "Liverpool", + "badge": "liverpool-badge" + } + }, + "sources": [ + { + "source": "alpha", + "id": "mu-liv-123" }, - "sources": [ - { - "source": "alpha", - "id": "mu-liv-123" - }, - { - "source": "bravo", - "id": "456-mu-liv" - } - ] - } - ] - ``` + { + "source": "bravo", + "id": "456-mu-liv" + } + ] + } + ] + ``` ### Streams The Streams API provides access to live streaming sources for sports events. #### Stream Object Structure + ```typescript interface Stream { - id: string; - streamNo: number; - language: string; - hd: boolean; - embedUrl: string; - source: string; + id: string; + streamNo: number; + language: string; + hd: boolean; + embedUrl: string; + source: string; } ``` #### Get Stream Links -* **Endpoints:** - * `GET /api/stream/alpha/[id]` - * `GET /api/stream/bravo/[id]` - * `GET /api/stream/charlie/[id]` - * `GET /api/stream/delta/[id]` - * `GET /api/stream/echo/[id]` - * `GET /api/stream/foxtrot/[id]` - * `GET /api/stream/golf/[id]` - * `GET /api/stream/hotel/[id]` - * `GET /api/stream/intel/[id]` -* **Method:** `GET` -* **Description:** Retrieves stream links for a specific match from a specific source. The `[id]` placeholder should be replaced with the source-specific match ID obtained from the match's `sources` array. -* **Example Request:** - ```bash - curl https://streamed.pk/api/stream/alpha/mu-liv-123 - ``` -* **Example Response:** - ```json - [ - { - "id": "stream_456", - "streamNo": 1, - "language": "English", - "hd": true, - "embedUrl": "https://example.com/embed/stream_456", - "source": "alpha" - } - ] - ``` +- **Endpoints:** + - `GET /api/stream/alpha/[id]` + - `GET /api/stream/bravo/[id]` + - `GET /api/stream/charlie/[id]` + - `GET /api/stream/delta/[id]` + - `GET /api/stream/echo/[id]` + - `GET /api/stream/foxtrot/[id]` + - `GET /api/stream/golf/[id]` + - `GET /api/stream/hotel/[id]` + - `GET /api/stream/intel/[id]` +- **Method:** `GET` +- **Description:** Retrieves stream links for a specific match from a specific source. The `[id]` placeholder should be replaced with the source-specific match ID obtained from the match's `sources` array. +- **Example Request:** + ```bash + curl https://streamed.pk/api/stream/alpha/mu-liv-123 + ``` +- **Example Response:** + ```json + [ + { + "id": "stream_456", + "streamNo": 1, + "language": "English", + "hd": true, + "embedUrl": "https://example.com/embed/stream_456", + "source": "alpha" + } + ] + ``` ### Sports The Sports API provides access to all available sport categories on the Streamed platform. #### Sport Object Structure + ```typescript interface Sport { - id: string; // Sport identifier (used in Matches API endpoints) - name: string; // Display name of the sport + id: string; // Sport identifier (used in Matches API endpoints) + name: string; // Display name of the sport } ``` #### Get Available Sports -* **Endpoint:** `/api/sports` -* **Method:** `GET` -* **Description:** Retrieves a list of available sports categories. -* **Example Request:** - ```bash - curl https://streamed.pk/api/sports - ``` -* **Example Response:** - ```json - [ - { - "id": "football", - "name": "Football" - }, - { - "id": "basketball", - "name": "Basketball" - }, - { - "id": "tennis", - "name": "Tennis" - } - ] - ``` +- **Endpoint:** `/api/sports` +- **Method:** `GET` +- **Description:** Retrieves a list of available sports categories. +- **Example Request:** + ```bash + curl https://streamed.pk/api/sports + ``` +- **Example Response:** + ```json + [ + { + "id": "football", + "name": "Football" + }, + { + "id": "basketball", + "name": "Basketball" + }, + { + "id": "tennis", + "name": "Tennis" + } + ] + ``` ### Images @@ -187,36 +190,36 @@ The Images API provides access to visual assets like team badges and match poste #### Get Team Badges -* **Endpoint:** `/api/images/badge/[id].webp` -* **Method:** `GET` -* **Description:** Retrieves a team's badge. The `[id]` is found in the `team.badge` field of the match object. -* **Example Request:** - ```bash - curl https://streamed.pk/api/images/badge/man-utd-badge.webp - ``` -* **Example Response:** - *Returns the image file.* +- **Endpoint:** `/api/images/badge/[id].webp` +- **Method:** `GET` +- **Description:** Retrieves a team's badge. The `[id]` is found in the `team.badge` field of the match object. +- **Example Request:** + ```bash + curl https://streamed.pk/api/images/badge/man-utd-badge.webp + ``` +- **Example Response:** + _Returns the image file._ #### Get Match Posters -* **Endpoint:** `/api/images/poster/[badge]/[badge].webp` -* **Method:** `GET` -* **Description:** Retrieves a match poster. `[badge]` values are typically derived from team badge IDs for the match. -* **Example Request:** - ```bash - curl https://streamed.pk/api/images/poster/man-utd-badge/liverpool-badge.webp - ``` -* **Example Response:** - *Returns the image file.* +- **Endpoint:** `/api/images/poster/[badge]/[badge].webp` +- **Method:** `GET` +- **Description:** Retrieves a match poster. `[badge]` values are typically derived from team badge IDs for the match. +- **Example Request:** + ```bash + curl https://streamed.pk/api/images/poster/man-utd-badge/liverpool-badge.webp + ``` +- **Example Response:** + _Returns the image file._ #### Get Proxied Images -* **Endpoint:** `/api/images/proxy/[poster].webp` -* **Method:** `GET` -* **Description:** Retrieves a proxied image. The `[poster]` is found in the `poster` field of the match object. -* **Example Request:** - ```bash - curl https://streamed.pk/api/images/proxy/custom-event-poster.webp - ``` -* **Example Response:** - *Returns the image file.* +- **Endpoint:** `/api/images/proxy/[poster].webp` +- **Method:** `GET` +- **Description:** Retrieves a proxied image. The `[poster]` is found in the `poster` field of the match object. +- **Example Request:** + ```bash + curl https://streamed.pk/api/images/proxy/custom-event-poster.webp + ``` +- **Example Response:** + _Returns the image file._ diff --git a/FireStoreRules.md b/FireStoreRules.md index 008ac73..f11746c 100644 --- a/FireStoreRules.md +++ b/FireStoreRules.md @@ -1,13 +1,13 @@ rules_version = '2'; service cloud.firestore { - match /databases/{database}/documents { - // --- Helper Functions --- - +match /databases/{database}/documents { +// --- Helper Functions --- + // Check if user is signed in function isAuthenticated() { return request.auth != null; } - + // Check if the user is accessing their own user document (where docId == userId) function isOwner(userId) { return isAuthenticated() && request.auth.uid == userId; @@ -55,7 +55,7 @@ service cloud.firestore { match /users/{userId}/watchlist/{document=**} { allow read, write: if isOwner(userId); } - + match /users/{userId}/history/{document=**} { allow read, write: if isOwner(userId); } @@ -69,7 +69,7 @@ service cloud.firestore { allow update: if isResourceOwner() && isRequestOwner(); allow delete: if isResourceOwner(); } - + match /favorites/{documentId} { allow read: if isResourceOwner(); allow create: if isRequestOwner(); @@ -85,9 +85,10 @@ service cloud.firestore { } // --- Default Deny --- - + match /{document=**} { allow read, write: if false; } - } -} \ No newline at end of file + +} +} diff --git a/index.html b/index.html index 759acf2..c4df091 100644 --- a/index.html +++ b/index.html @@ -16,7 +16,10 @@ href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@300;400;500;600;700&display=swap" /> - +