Migration to last.fm, removed old spotify api client. FOSRestBundle API serving data driven front end (JWT).
This commit is contained in:
1 parent
391ecf1732
commit
56dea097d6
51 files changed
+1749
-844
No files matched your search
@@ -23,7 +23,7 @@
|
||||
|
||||
## Site settings (ROLE_ADMIN)
|
||||
- URL: `/admin/settings`
|
||||
- Form persists Spotify Client ID/Secret in the DB (no restart needed).
|
||||
- Form persists Last.fm API key in the DB (no restart needed).
|
||||
- Toggle “Allow self-service registration” to pause public sign-ups while keeping `/admin/users` creation available to staff.
|
||||
- The setting syncs with the `APP_ALLOW_REGISTRATION` environment variable each time Symfony boots (change the env value and restart to enforce). UI changes persist while the process runs.
|
||||
- CSRF + role guards prevent unauthorized updates.
|
||||
@@ -44,5 +44,5 @@ docker compose exec php php bin/console app:promote-moderator user@example.com
|
||||
|
||||
## Useful tips
|
||||
- Registration toggle can be locked by environment (`APP_ALLOW_REGISTRATION`), in which case the UI explains that the value is immutable.
|
||||
- Changing Spotify credentials in settings is effective immediately; no restart is required.
|
||||
- Changing Last.fm credentials in settings is effective immediately; no restart is required.
|
||||
- Admin UI actions are CSRF‑protected and role‑checked; if a button appears disabled, hover for a tooltip explanation.
|
||||
+12
-14
@@ -6,19 +6,19 @@ This project follows a conventional Symfony architecture with clear separation o
|
||||
|
||||
- **Classes**
|
||||
- **Controllers** end with `Controller` (e.g. `AlbumController`) and expose HTTP‑oriented actions with verb‑based method names (`search`, `show`, `edit`, `delete`).
|
||||
- **Services** are named by capability, not by caller, using nouns or noun‑phrases (e.g. `AlbumSearchService`, `ConsoleCommandRunner`, `RegistrationToggle`). When a service is tightly scoped to a third‑party, the integration appears in the name (e.g. `SpotifyClient`, `SpotifyMetadataRefresher`).
|
||||
- **Services** are named by capability, not by caller, using nouns or noun‑phrases (e.g. `AlbumSearchService`, `ConsoleCommandRunner`, `RegistrationToggle`). When a service is tightly scoped to a third‑party, the integration appears in the name (e.g. `LastFmClient`, `LastFmMetadataRefresher`).
|
||||
- **Entities** are singular domain nouns (`Album`, `Review`, `User`) and avoid transport or UI details.
|
||||
- **Commands** describe what they do and the environment they are meant for (e.g. `SeedDemoUsersCommand`, `PromoteAdminCommand`).
|
||||
|
||||
- **Methods**
|
||||
- Use **verb‑based, intention‑revealing names** that describe *what* the method does, not *how* it is used (e.g. `refreshAllSpotifyAlbums()`, `resetCatalog()`, `runConsoleCommand()`, `isEnabled()`, `findAlbumByPublicId()`).
|
||||
- Accessors start with `get*`, `set*`, `is*` / `has*` for booleans (e.g. `getEnvOverride()`, `isSpotifyConfigured()`).
|
||||
- Use **verb‑based, intention‑revealing names** that describe *what* the method does, not *how* it is used (e.g. `refreshAllExternalAlbums()`, `resetCatalog()`, `runConsoleCommand()`, `isEnabled()`, `findAlbumByPublicId()`).
|
||||
- Accessors start with `get*`, `set*`, `is*` / `has*` for booleans (e.g. `getEnvOverride()`, `isExternalConfigured()`).
|
||||
- Avoid ambiguous names like `run()`, `handle()`, or `process()` without a clear domain object; prefer `runConsoleCommand()`, `handleAlbumCoverUpload()`, etc.
|
||||
|
||||
- **Variables & parameters**
|
||||
- Use **descriptive, domain‑level names** (e.g. `$albumRepository`, `$reviewCount`, `$spotifyAlbumPayload`) and avoid unclear abbreviations (`$em` is acceptable for `EntityManagerInterface` in local scope, but prefer full names for properties).
|
||||
- Booleans read naturally (`$isEnabled`, `$shouldQuerySpotify`, `$needsSync`).
|
||||
- Collections are pluralized (`$albums`, `$userReviews`, `$spotifyIds`).
|
||||
- Use **descriptive, domain‑level names** (e.g. `$albumRepository`, `$reviewCount`, `$lastfmAlbumPayload`) and avoid unclear abbreviations (`$em` is acceptable for `EntityManagerInterface` in local scope, but prefer full names for properties).
|
||||
- Booleans read naturally (`$isEnabled`, `$shouldQueryLast.fm`, `$needsSync`).
|
||||
- Collections are pluralized (`$albums`, `$userReviews`, `$lastfmIds`).
|
||||
|
||||
- **Files & namespaces**
|
||||
- File names match their primary class name and follow PSR‑4 (e.g. `src/Service/AlbumSearchService.php` for `App\Service\AlbumSearchService`).
|
||||
@@ -27,10 +27,10 @@ This project follows a conventional Symfony architecture with clear separation o
|
||||
These conventions should be followed for all new PHP code and when refactoring existing classes to keep the codebase reusable and self‑documenting.
|
||||
|
||||
## High-level flow
|
||||
1. Visitors search for albums (Spotify) and view an album page
|
||||
1. Visitors search for albums (Last.fm) and view an album page
|
||||
2. Logged‑in users can write, edit, and delete reviews
|
||||
3. Moderators and admins can moderate content and manage users
|
||||
4. Admins configure site settings (Spotify credentials, registration toggle)
|
||||
4. Admins configure site settings (Last.fm credentials, registration toggle)
|
||||
|
||||
## Layers & components
|
||||
|
||||
@@ -45,7 +45,7 @@ These conventions should be followed for all new PHP code and when refactoring e
|
||||
- `User` — authentication principal and roles
|
||||
- `Album`, `AlbumTrack` — normalized album metadata and track list
|
||||
- `Review` — user‑authored review with rating and timestamps
|
||||
- `Setting` — key/value store for site configuration (e.g., Spotify credentials)
|
||||
- `Setting` — key/value store for site configuration (e.g., Last.fm credentials)
|
||||
|
||||
### Repositories (`src/Repository/*`)
|
||||
- Doctrine repositories for querying by domain (albums, tracks, reviews, settings, users)
|
||||
@@ -55,10 +55,10 @@ These conventions should be followed for all new PHP code and when refactoring e
|
||||
- Leverage Symfony validation constraints for robust server‑side validation
|
||||
|
||||
### Services (`src/Service/*`)
|
||||
- `SpotifyClient` — Client Credentials token management (cached) and API calls
|
||||
- `SpotifyMetadataRefresher`, `SpotifyGenreResolver` — helpers for richer album data
|
||||
- `LastFmClient` — Last.fm API integration with caching
|
||||
- `LastFmMetadataRefresher`, `LastFmTagResolver` — helpers for richer album data
|
||||
- `CatalogResetService` — admin action to reset/sync catalog state safely
|
||||
- `ImageStorage` — avatar uploads and related image handling
|
||||
- `UploadStorage` — avatar/album image uploads and related file handling
|
||||
- `RegistrationToggle` — DB‑backed registration flag with env override
|
||||
|
||||
### Security (`config/packages/security.yaml`, `src/Security/*`)
|
||||
@@ -86,5 +86,3 @@ These conventions should be followed for all new PHP code and when refactoring e
|
||||
## Testing & tooling
|
||||
- PHPUnit setup in `composer.json` (`phpunit/phpunit`), BrowserKit & CSS Selector for functional coverage
|
||||
- Web Profiler enabled in dev
|
||||
|
||||
|
||||
+2
-4
@@ -18,8 +18,7 @@ docker run -d \
|
||||
-p 8080:8080 \
|
||||
-e APP_ENV=prod \
|
||||
-e APP_SECRET=change_me \
|
||||
-e SPOTIFY_CLIENT_ID=your_client_id \
|
||||
-e SPOTIFY_CLIENT_SECRET=your_client_secret \
|
||||
-e LASTFM_API_KEY=your_api_key \
|
||||
tonehaus-app:latest
|
||||
```
|
||||
|
||||
@@ -51,7 +50,7 @@ docker exec tonehaus php bin/console doctrine:migrations:migrate --no-interactio
|
||||
## Environment variables
|
||||
- `APP_ENV` (`prod` recommended in production)
|
||||
- `APP_SECRET` (required; random string)
|
||||
- `SPOTIFY_CLIENT_ID`, `SPOTIFY_CLIENT_SECRET`
|
||||
- `LASTFM_API_KEY`
|
||||
- `APP_ALLOW_REGISTRATION` (env override for public registration)
|
||||
- `DATABASE_DRIVER` (`sqlite` default, or `postgres`)
|
||||
- `DATABASE_URL` (when using Postgres)
|
||||
@@ -67,4 +66,3 @@ docker exec tonehaus php bin/console doctrine:migrations:migrate --no-interactio
|
||||
- Build then run a new container alongside the old one, switch traffic at the proxy
|
||||
- Keep SQLite on a named volume, or use Postgres for shared state across replicas
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
# Features
|
||||
|
||||
## Albums & Reviews
|
||||
- Spotify album search with advanced filters (album, artist, year range)
|
||||
- Last.fm album search with advanced filters (album, artist, year range)
|
||||
- Album page: cover art, metadata, full tracklist (when available)
|
||||
- Reviews list (newest first) and inline new review form (logged-in)
|
||||
- Rating slider (1–10) with live badge
|
||||
@@ -16,7 +16,7 @@
|
||||
## Administration
|
||||
- Dashboard: latest reviews/albums and key counts (moderator+)
|
||||
- Users: create/delete users, promote/demote moderators (admin constraints)
|
||||
- Settings: manage Spotify credentials, toggle public registration (admin)
|
||||
- Settings: manage Last.fm credentials, toggle public registration (admin)
|
||||
|
||||
## Design & UX
|
||||
- Responsive Bootstrap UI
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Last.fm Integration
|
||||
|
||||
## Credentials
|
||||
- Preferred: manage the Last.fm API key in `/admin/settings` (persisted in DB; no restart required).
|
||||
- Env fallback: `LASTFM_API_KEY`.
|
||||
|
||||
## API Client
|
||||
- `src/Service/LastFmClient.php` (uses Guzzle)
|
||||
- `searchAlbums(query, limit)`
|
||||
- `getAlbum(id)` / `getAlbums([ids])`
|
||||
- `getAlbumWithTracks(id)`
|
||||
- `getAlbumTracks(id)`
|
||||
|
||||
## Caching & Limits
|
||||
- Last.fm responses are cached in Symfony cache pools to reduce repeated calls.
|
||||
- Search/detail payloads are normalized to one internal album shape before persistence.
|
||||
|
||||
## Ingestion Flow
|
||||
1. Search Last.fm
|
||||
2. Resolve tags/genres via `LastFmTagResolver`
|
||||
3. Persist or update album with `AlbumRepository::upsertFromExternalAlbum()`
|
||||
4. Persist tracks with `AlbumTrackRepository::replaceAlbumTracks()`
|
||||
|
||||
## Admin Settings
|
||||
- Set the Last.fm API key in `/admin/settings`.
|
||||
- Key changes apply immediately.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Album page
|
||||
- Artwork, metadata, average rating, and review count
|
||||
- Full Spotify tracklist when available
|
||||
- Full Last.fm tracklist when available
|
||||
- Reviews list (newest first)
|
||||
- Inline new review form for logged‑in users
|
||||
|
||||
|
||||
+12
-7
@@ -2,7 +2,7 @@
|
||||
|
||||
## Prerequisites
|
||||
- Docker + Docker Compose
|
||||
- Spotify Developer account (Client ID/Secret)
|
||||
- Last.fm API key
|
||||
- A unique `APP_SECRET` value in your environment (for prod builds)
|
||||
|
||||
## 1) Start the stack
|
||||
@@ -18,15 +18,19 @@ Health: `http://localhost:8085/healthz`
|
||||
docker compose exec tonehaus php bin/console app:promote-admin you@example.com
|
||||
```
|
||||
|
||||
## 3) Configure Spotify
|
||||
- Preferred: open `/admin/settings` and enter your Client ID/Secret (stored in DB)
|
||||
## 3) Configure Last.fm
|
||||
- Preferred: open `/admin/settings` and enter your Last.fm API key (stored in DB)
|
||||
- Env fallback (in `.env` or your shell):
|
||||
```bash
|
||||
SPOTIFY_CLIENT_ID=your_client_id
|
||||
SPOTIFY_CLIENT_SECRET=your_client_secret
|
||||
LASTFM_API_KEY=your_api_key
|
||||
```
|
||||
|
||||
## 4) (Optional) Seed demo data
|
||||
## 4) JWT auth keys
|
||||
- API login endpoint: `POST /api/v1/auth/login`
|
||||
- JWT keys are generated automatically on container start into `config/jwt/`.
|
||||
- Set `JWT_PASSPHRASE` in `.env` to your production secret.
|
||||
|
||||
## 5) (Optional) Seed demo data
|
||||
```bash
|
||||
docker compose exec tonehaus php bin/console app:seed-demo-users --count=50
|
||||
docker compose exec tonehaus php bin/console app:seed-demo-albums --count=40 --attach-users
|
||||
@@ -44,7 +48,8 @@ docker compose exec tonehaus php bin/console app:seed-demo-reviews --cover-perce
|
||||
## Environment variables
|
||||
- `APP_ENV=dev|prod`
|
||||
- `APP_SECRET=<random_string>`
|
||||
- `SPOTIFY_CLIENT_ID`, `SPOTIFY_CLIENT_SECRET`
|
||||
- `LASTFM_API_KEY`
|
||||
- `JWT_PASSPHRASE=<random_string>`
|
||||
- `APP_ALLOW_REGISTRATION=1|0` (env can override DB setting)
|
||||
- `DATABASE_DRIVER=sqlite|postgres`
|
||||
- `DATABASE_SQLITE_PATH` (optional)
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# Spotify Integration
|
||||
|
||||
## Credentials
|
||||
- Preferred: Manage in `/admin/settings` (persisted in DB; no restart required)
|
||||
- Env fallback: `SPOTIFY_CLIENT_ID`, `SPOTIFY_CLIENT_SECRET`
|
||||
|
||||
## API Client
|
||||
- `src/Service/SpotifyClient.php`
|
||||
- Client Credentials token fetch with caching
|
||||
- `searchAlbums(q, limit)` — album search endpoint
|
||||
- `getAlbum(id)` / `getAlbums([ids])` — metadata fetch
|
||||
- `getAlbumWithTracks(id)` — metadata + hydrated tracklist
|
||||
- `getAlbumTracks(id)` — raw paginated tracks (when needed)
|
||||
|
||||
### Caching & Rate Limits
|
||||
- Access tokens are cached until expiry to avoid unnecessary auth calls.
|
||||
- Downstream requests should be mindful of Spotify rate limits; user actions are debounced in the UI and server calls are focused on album/track data needed by the current page.
|
||||
|
||||
## Advanced search syntax
|
||||
- Fielded queries are composed as:
|
||||
- `album:"..."`, `artist:"..."`, `year:YYYY` or `year:YYYY-YYYY`
|
||||
- Optional free text is appended to the query
|
||||
- Examples:
|
||||
- `album:"in rainbows" artist:"radiohead"`
|
||||
- `year:1999-2004 post rock`
|
||||
|
||||
## Admin settings
|
||||
- Update credentials in `/admin/settings`
|
||||
- Settings are stored in the database; `APP_ENV` reload or container restart is not required
|
||||
|
||||
@@ -29,9 +29,8 @@
|
||||
postgresql://symfony:symfony@db:5432/symfony?serverVersion=16&charset=utf8
|
||||
```
|
||||
|
||||
## Spotify errors
|
||||
- Verify credentials in `/admin/settings` or env vars `SPOTIFY_CLIENT_ID` / `SPOTIFY_CLIENT_SECRET`.
|
||||
- Client Credentials tokens are cached; if revoked, wait for expiry or restart the container.
|
||||
## Last.fm errors
|
||||
- Verify credentials in `/admin/settings` or env var `LASTFM_API_KEY`.
|
||||
|
||||
## ARM64 Build
|
||||
|
||||
@@ -43,4 +42,4 @@ sudo docker buildx build \
|
||||
-f docker/php/Dockerfile \
|
||||
. \
|
||||
--load
|
||||
```
|
||||
```
|
||||
Reference in new issue
Block a user