{"id":29276418,"url":"https://github.com/bravorod/bookcompany","last_synced_at":"2026-02-07T00:02:51.036Z","repository":{"id":250683385,"uuid":"473006097","full_name":"bravorod/bookcompany","owner":"bravorod","description":"Full-stack PWA media library with Firebase \u0026 GraphQL: SSR/SSG, offline caching, real-time Firestore sync, OAuth2 SSO, NgRx state, dynamic theming, NYT integration, CI/CD pipelines, E2E Tests, and Sentry error tracking","archived":false,"fork":false,"pushed_at":"2025-07-11T09:35:16.000Z","size":5044,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"solo-main","last_synced_at":"2025-10-25T03:44:45.035Z","etag":null,"topics":["angular","authentication","backend","cloud-native","content-platform","deployment","e2e-tests","firebase","frontend","fullstack","google-cloud","javascript","material-ui","media-library","ngrx","pwa","responsive-design","rest-api","typescript","webapp"],"latest_commit_sha":null,"homepage":"https://bookcompanyus.com","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/bravorod.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}},"created_at":"2022-03-23T02:12:25.000Z","updated_at":"2025-07-11T09:40:30.000Z","dependencies_parsed_at":"2024-07-29T12:47:35.193Z","dependency_job_id":"ef41bc87-fb77-4d2d-97d4-847f0f8e4e75","html_url":"https://github.com/bravorod/bookcompany","commit_stats":null,"previous_names":["rodrigo-bravo/bookcompany","bravorod/bookcompany"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bravorod/bookcompany","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bravorod%2Fbookcompany","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bravorod%2Fbookcompany/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bravorod%2Fbookcompany/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bravorod%2Fbookcompany/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bravorod","download_url":"https://codeload.github.com/bravorod/bookcompany/tar.gz/refs/heads/solo-main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bravorod%2Fbookcompany/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29181265,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-06T23:15:33.022Z","status":"ssl_error","status_checked_at":"2026-02-06T23:15:09.128Z","response_time":59,"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":["angular","authentication","backend","cloud-native","content-platform","deployment","e2e-tests","firebase","frontend","fullstack","google-cloud","javascript","material-ui","media-library","ngrx","pwa","responsive-design","rest-api","typescript","webapp"],"created_at":"2025-07-05T08:11:18.382Z","updated_at":"2026-02-07T00:02:51.029Z","avatar_url":"https://github.com/bravorod.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  \u003cspan style=\"color:#1976d2\"\u003eBook\u003c/span\u003e\u003cspan style=\"color:#d32f2f\"\u003eCompany\u003c/span\u003e\n\u003c/h1\u003e\n\n\n\u003cdiv align=\"center\"\u003e\n  \u003cstrong\u003eA full-stack, cloud-native media library for books, songs, and podcasts\u003c/strong\u003e\u003cbr\u003e\n  \u003cem\u003eBuilt with Angular, Firebase, NgRx, and integrated REST APIs — deployed on Firebase Hosting\u003c/em\u003e\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://brandslogos.com/wp-content/uploads/images/large/angular-icon-logo.png\" width=\"40\" title=\"Angular\"/\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/89810908/160763806-50c19cfc-98ab-4095-bf1d-30fabc2dbc8b.png\" width=\"40\" title=\"Firebase\"/\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/89810908/160764123-df74b910-317e-4b11-a670-6a6bd582e685.svg\" width=\"40\" title=\"TypeScript\"/\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/89810908/160764862-abab2359-43b5-47ae-a105-556b7322c774.png\" width=\"40\" title=\"Google Cloud\"/\u003e\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/89810908/158899092-e7a3fe32-f36f-42c7-a236-c3d1c112ff98.gif\" width=\"100%\" alt=\"BookCompany Demo\"/\u003e\n\u003c/div\u003e\n\u003cdiv align=\"center\"\u003e\n\n  [![Build](https://img.shields.io/badge/build-passing-brightgreen)]()\n  [![Tech](https://img.shields.io/badge/Angular-13-red)]()\n  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n\u003c/div\u003e\n\n\n---\n\n## 💻 Live Demo  \n[BookCompany](https://bookcompany.web.app) \n\n---\n\n## 🌟 Features at a Glance\n\n- 🔐 **User Authentication** with Firebase (Google + Email)\n- 📍 **Google Maps \u0026 Directions API** for media-based landmark lookup\n- 📚 **NYT Books API** for Best Sellers \u0026 Book Reviews\n- 🧾 **Personal Collection Manager** — Add, edit, and delete media items\n- ⚡ **NgRx State Management** for scalable and reactive data flow\n- 🎨 **Responsive UI** with Angular Material + Bootstrap 5\n- ☁️ **Cloud-hosted** via Firebase for real-time access and deployment\n\n---\n\n## Usage Analytics \u0026 Tracking\n\nUser interactions (e.g. searches, collection edits, profile updates) are event-driven and can be extended to track usage metrics. These logs simulate behavioral data that can be used for KPIs, retention analysis, or ML-based personalization.\n\n---\n\n## Tech Stack\n\n| Frontend     | Backend         | APIs / Integrations         | DevOps / Hosting     |\n|--------------|------------------|------------------------------|------------------------|\n| Angular 13   | Firebase Firestore | Google Maps, NYTimes Books   | Firebase Hosting        |\n| TypeScript   | Firebase Auth     | NgRx, RxJS, Chart.js         | GitHub + CLI Deploy     |\n\n\u003e ⚙The combination of NgRx and Firebase Firestore simulates a reactive event pipeline — user actions trigger state changes and DB syncs, modeling ingestion + transformation + storage flow.\n\n\n---\n\n## Purpose \u0026 Vision\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://avatars.githubusercontent.com/u/9950313?s=200\u0026v=4\" alt=\"Node.js logo\" height=\"20\"/\u003e\n\u003c/div\u003e\n\u003cbr/\u003e\n\nI created BookCompany to explore building a scalable, full-stack Angular application with real-world API integrations, authentication flows, and dynamic state management — all deployed serverlessly with Firebase. I wanted to simulate a professional-grade project architecture from end to end.\n\n\n\n---\n\n## Future Work (Version 1.2): ML Integration\n\nCollected user behavior and media activity can be extended into ML pipelines for recommendations, engagement scoring, or media classification. This structure supports supervised and unsupervised modeling workflows via exportable Firestore logs.\n\n\n---\n\n## Full Feature Gallery\n\u003cdiv align=\"center\"\u003e\n  \u003ctable width=\"100%\"\u003e\n    \u003ctr\u003e\n      \u003cth align=\"center\"\u003eLanding Page\u003c/th\u003e\n      \u003cth align=\"center\"\u003eLogged-In Dashboard\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003cimg src=\"https://user-images.githubusercontent.com/89810908/160753926-b8c8bc23-5ad2-40aa-8f46-01b6b94a7632.PNG\" width=\"100%\"\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003cimg src=\"https://user-images.githubusercontent.com/89810908/158890254-6ad1f21b-bc46-464d-a344-76fc0700fc05.PNG\" width=\"100%\"\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\n\n\u003cbr/\u003e\n\n\u003e Click any section below to expand screenshots of BookCompany's APIs, authentication flows, and media management system.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🧩 Integrated REST APIs\u003c/strong\u003e\u003c/summary\u003e\n\n### 📍 Google Maps Platform\n\n\u003cdiv align=\"center\"\u003e\u003cb\u003eLandmarks Search Page\u003c/b\u003e\u003c/div\u003e\u003cbr/\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/89810908/158891867-e514ee07-fd02-4183-b2ea-1b2d84e73f92.PNG\" width=\"100%\"\u003e\n\n\u003chr style=\"border: none; border-top: 1px solid #ccc; margin: 1.5em 0;\" /\u003e\n\n### 🎞️ NYT Books API\n\n\u003cdiv align=\"center\"\u003e\u003cb\u003eBook Reviews Page\u003c/b\u003e\u003c/div\u003e\u003cbr/\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/89810908/159611574-fc281cb3-9e9e-402f-b7c1-9555c3ddf53c.PNG\" width=\"100%\"\u003e\n\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\u003cb\u003eBest Sellers Page\u003c/b\u003e\u003c/div\u003e\u003cbr/\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/89810908/159611584-457d7796-fb04-466e-b599-e1d510647ef3.PNG\" width=\"100%\"\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e🔐 Authentication \u0026 Registration\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\u003cb\u003eLogin Page\u003c/b\u003e\u003c/div\u003e\u003cbr/\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/89810908/158891203-a0a8d0e9-4f90-401a-a938-41a41a1263ad.png\" width=\"100%\"\u003e\n\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\u003cb\u003eRegister Page\u003c/b\u003e\u003c/div\u003e\u003cbr/\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/89810908/158891534-cbf296e3-cd2c-4bb5-8161-e0cbb5942972.PNG\" width=\"100%\"\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e👤 User Profile\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\u003cb\u003eProfile Page\u003c/b\u003e\u003c/div\u003e\u003cbr/\u003e\n\u003cimg src=\"https://user-images.githubusercontent.com/89810908/158890981-006bb162-5133-4fda-8ca0-1a3a6af52f31.PNG\" width=\"100%\"\u003e\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e📦 Personal Media Collection (CRUD)\u003c/strong\u003e\u003c/summary\u003e\n\u003cbr/\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ctable width=\"100%\"\u003e\n    \u003ctr\u003e\n      \u003cth align=\"center\"\u003eCreate Media\u003c/th\u003e\n      \u003cth align=\"center\"\u003eUpdate Media\u003c/th\u003e\n      \u003cth align=\"center\"\u003eDelete Media\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003cimg src=\"https://user-images.githubusercontent.com/89810908/160908939-33dbb4b3-724f-4e10-937b-32808c7ba63b.PNG\" width=\"100%\"\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003cimg src=\"https://user-images.githubusercontent.com/89810908/160909122-26e41d4a-da1c-47ea-adea-d77117436dac.PNG\" width=\"100%\"\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003cimg src=\"https://user-images.githubusercontent.com/89810908/160909071-86609fa4-74db-4cd3-a246-225fe95a9f21.PNG\" width=\"100%\"\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/table\u003e\n\u003c/div\u003e\n\u003c/details\u003e\n\n---\n\n\n## Getting Started\n\nSet up BookCompany locally or in the cloud in just a few steps. This guide walks you through all dependencies, configuration files, and deployment requirements.\n\n## Prerequisites\n\nSet up the following tools and accounts:\n\n- ✅ **[Node.js \u0026 npm](https://nodejs.org/en/)**\n- ✅ **[Firebase Console](https://console.firebase.google.com/)** project (Firestore, Hosting, Authentication)\n- ✅ **[Google Cloud Console](https://console.cloud.google.com/)** with Maps JavaScript API and Places API enabled\n- ✅ **[NYTimes Developer Account](https://developer.nytimes.com/)** for the Books API\n- ✅ **Angular CLI**\n  ```bash\n  npm install -g @angular/cli\n  ```\n\n## Local Installation\n\n1. **Clone the Repository**\n   ```bash\n   git clone https://github.com/bravorod/bookcompany.git\n   cd bookcompany\n   ```\n\n2. **Install Dependencies**\n   ```bash\n   npm install\n   ```\n\n3. **Configure Environment Variables**\n\n   Create the following files inside `src/environments/`:\n\n   - `environment.ts`\n   - `environment.prod.ts`\n\n   Paste this example inside each:\n\n   ```ts\n   export const environment = {\n     production: false,\n     firebaseConfig: {\n       apiKey: 'YOUR_FIREBASE_API_KEY',\n       authDomain: 'your-project.firebaseapp.com',\n       projectId: 'your-project-id',\n       storageBucket: 'your-project.appspot.com',\n       messagingSenderId: 'YOUR_SENDER_ID',\n       appId: 'YOUR_APP_ID'\n     },\n     nytApiKey: 'YOUR_NYT_BOOKS_API_KEY',\n     googleMapsApiKey: 'YOUR_GOOGLE_MAPS_API_KEY'\n   };\n   ```\n\n4. **Run the App Locally**\n   ```bash\n   ng serve\n   ```\n\n## Cloud Deployment\n\n1. **Login and Initalize Firebase CLI and Initalize**\n   ```bash\n   firebase login\n\n   firebase init\n   ```\n   Enable:\n   - Hosting\n   - Firestore\n   - Authentication\n\n2. **Build the App**\n   ```bash\n   ng build --prod\n   ```\n\n3. **Deploy to Firebase**\n   ```bash\n   firebase deploy\n   ```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003e❗ Troubleshooting\u003c/strong\u003e\u003c/summary\u003e\n\n- **❌ Error:** `Firebase: Missing config object`  \n  **Fix:** Make sure your `environment.ts` and `environment.prod.ts` are correctly configured with valid Firebase keys.\n\n- **❌ Error:** Google Maps not loading  \n  **Fix:** make sure that both the **Maps JavaScript API** and **Places API** are enabled in your Google Cloud Console and that billing is set up.\n\n- **❌ Error:** `Authentication error` during login  \n  **Fix:** Make sure you've enabled **Email/Password**, **Google**, or **Twitter** authentication in the Firebase console.\n\n- **❌ Error:** `ng: command not found`  \n  **Fix:** Install Angular CLI globally:  \n  ```bash\n  npm install -g @angular/cli\n  ```\n\n\u003c/details\u003e\n\n---\n\n## Unit Tests\n\n```bash\nng test\n```\n\n```ts\ndescribe('LoginComponent', () =\u003e {\n  let component: LoginComponent;\n  let fixture: ComponentFixture\u003cLoginComponent\u003e;\n\n  beforeEach(async () =\u003e {\n    await TestBed.configureTestingModule({\n      declarations: [LoginComponent],\n      imports: [ReactiveFormsModule]\n    }).compileComponents();\n\n    fixture = TestBed.createComponent(LoginComponent);\n    component = fixture.componentInstance;\n    fixture.detectChanges();\n  });\n\n  it('should render login form', () =\u003e {\n    const compiled = fixture.nativeElement as HTMLElement;\n    expect(compiled.querySelector('form')).toBeTruthy();\n  });\n\n  it('should invalidate the form when empty', () =\u003e {\n    expect(component.loginForm.valid).toBeFalse();\n  });\n});\n```\n\n---\n\n## End-to-End (E2E) Tests\n\n```bash\nng e2e\n```\n\n```ts\nit('should navigate to the login page and show login form', async () =\u003e {\n  await page.navigateTo('/login');\n  expect(await page.getLoginFormTitle()).toEqual('Sign In');\n});\n```\n\n---\n\n## CI/CD Potential\n\nThis project can be integrated with GitHub Actions to automate testing, building, and deployment to Firebase Hosting. Workflow files (`.yml`) and configuration templates can be added to support continuous delivery and cloud deployment pipelines.\n\n---\n\n\n- [NYT Books API](https://developer.nytimes.com/)\n- [Google Maps Platform](https://console.cloud.google.com/google/maps-apis/start)\n- Angular, Firebase \u0026 NgRx community docs\n\n\u003c!-- SEO keywords --\u003e\n\u003c!--\nTech stack: Angular, Firebase, Firestore, NgRx, TypeScript, RxJS, REST API, Google Maps, NYTimes API, Authentication, CRUD, Bootstrap, Material UI, Protractor, Karma, Cloud Hosting\n--\u003e\n\n## Author\n\n**Rodrigo E. Bravo**  \n📫 rodrigoebravo@outlook.com  \n\u003cbr/\u003e\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbravorod%2Fbookcompany","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbravorod%2Fbookcompany","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbravorod%2Fbookcompany/lists"}