{"id":51261419,"url":"https://github.com/guseynov/spacex_explorer","last_synced_at":"2026-06-29T12:30:37.263Z","repository":{"id":362259609,"uuid":"1257327832","full_name":"guseynov/spacex_explorer","owner":"guseynov","description":"SpaceX Explorer — Next.js, TypeScript, TanStack Query, testing","archived":false,"fork":false,"pushed_at":"2026-06-13T04:41:31.000Z","size":174,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-13T06:23:53.263Z","etag":null,"topics":["frontend","nextjs","react","react-window","tailwindcss","tanstack-query","typescript","zod"],"latest_commit_sha":null,"homepage":"https://spacex-explorer-delta.vercel.app","language":"TypeScript","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/guseynov.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-06-02T15:17:10.000Z","updated_at":"2026-06-13T04:41:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/guseynov/spacex_explorer","commit_stats":null,"previous_names":["guseynov/spacex_explorer"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/guseynov/spacex_explorer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guseynov%2Fspacex_explorer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guseynov%2Fspacex_explorer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guseynov%2Fspacex_explorer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guseynov%2Fspacex_explorer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/guseynov","download_url":"https://codeload.github.com/guseynov/spacex_explorer/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/guseynov%2Fspacex_explorer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34927673,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["frontend","nextjs","react","react-window","tailwindcss","tanstack-query","typescript","zod"],"created_at":"2026-06-29T12:30:35.921Z","updated_at":"2026-06-29T12:30:37.258Z","avatar_url":"https://github.com/guseynov.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SpaceX Explorer\n\nSpaceX Explorer is a frontend take-home task made for Digt. It is built with Next.js, React, and TypeScript against the public Launch Library 2 API. It focuses on server-side pagination/filtering, typed API boundaries, accessible states, local favorites persistence, and list performance.\n\n## How to run\n\n```bash\nnpm install\nnpm run dev\n```\n\nOpen [http://localhost:3000](http://localhost:3000).\n\nUseful scripts:\n\n```bash\nnpm run lint\nnpm run build\nnpm run test:run\nnpm run test:e2e\n```\n\n## Stack and architecture decisions\n\n- `Next.js App Router`: the repo started empty, so App Router was the cleanest choice for route organization, metadata, and route-level loading/error ergonomics. The final routes are `/`, `/favorites`, and `/launches/[id]`.\n- `TanStack Query`: used for caching, deduplication, retry behavior, and load-more pagination. It is a better fit than custom fetch state because the task explicitly requires caching and background refresh behavior.\n- `Tailwind CSS`: used for fast, consistent styling with a small amount of global CSS for theme tokens and utility classes.\n- `Zod`: validates the Launch Library 2 response shape at the boundary; application code consumes those validated LL2 fields directly.\n- `react-window`: virtualizes the loaded launch list to keep rendering stable as pages accumulate.\n\n## Launch API usage\n\nBase API:\n\n- [https://ll.thespacedevs.com/2.3.0](https://ll.thespacedevs.com/2.3.0)\n\nEndpoints used:\n\n- `GET /launches/`\n- `GET /launches/:id/`\n\nPagination strategy:\n\n- The list uses LL2 offset pagination with `limit=12` and is restricted to SpaceX launch service provider ID `121`.\n- Filters are mapped to LL2 date, status, search, and ordering query parameters instead of fetching everything client-side.\n- Browser requests pass through `/api/launch-library`, which caches upstream GET responses for five minutes to respect the public API rate limit.\n- The yearly trends view downloads the requested date window in pages of 100 and aggregates locally instead of issuing two requests per year.\n\n## Performance and accessibility\n\nPerformance choices:\n\n- Loaded pages are rendered through `react-window`.\n- Search requests are debounced by 300ms.\n- React Query stale times are tuned by resource type:\n  - launch list: 60s\n  - launch detail: 60s\n- The trends page includes yearly SpaceX launch volume and success rate summaries sourced from Launch Library 2.\n- Retry policy only retries `429` and `5xx` responses, with a basic 500ms/1000ms backoff.\n- Favorites and compare selections persist in `localStorage`, so saved state survives reloads in the same browser.\n\nAccessibility choices:\n\n- Semantic headings and sections across list, favorites, and detail pages.\n- Labeled filter controls and visible keyboard focus styles.\n- `aria-live=\"polite\"` for list loading/result updates.\n- The launch list auto-loads the next page as you approach the end of the virtualized feed, while the live result text keeps pagination state readable.\n- Gallery images use descriptive alt text based on the mission name.\n\n## Tradeoffs, limitations, and next steps\n\nTradeoffs:\n\n- The launch list stays client-fetched so filters, search, and load-more remain responsive.\n- The launch detail route is server-rendered from one LL2 detailed launch response, which already embeds launcher configuration and pad data.\n- Launch list virtualization uses fixed row heights, so list cards intentionally keep content compact.\n- Compare mode is available at `/compare` and uses shareable `left`/`right` query params plus a local compare queue to seed selections from the explorer or detail pages.\n\nKnown limitations / TODOs:\n\n- External media uses `next/image` in unoptimized mode because remote image coverage is broad and the task is frontend-focused.\n- Browser coverage uses Playwright against the Next dev server and an LL2-shaped mock route, so the tests exercise the same contract as production without live network dependencies.\n- Offline app-shell caching is not implemented yet; that is a future improvement rather than a shipped feature.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguseynov%2Fspacex_explorer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguseynov%2Fspacex_explorer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguseynov%2Fspacex_explorer/lists"}