Skip to content

Conversation

@shaunburdick
Copy link
Owner

Summary

Implements backend API endpoints required for Android TV App Phase 2 (Channel Browsing & Video Streaming) and includes comprehensive Phase 2 planning documentation.

Phase 2 Scope: Channel list UI, HLS video playback, favorites integration, MVVM architecture

Backend Implementation ✅

New API Endpoints

1. POST /api/stream-token

  • Generates HMAC-SHA256 signed tokens for HLS video streaming
  • Token expiry: Configurable (default 12 hours)
  • Validates JWT session authentication (Cookie-based)
  • Verifies tuner and channel exist
  • Returns: { token, expiresAt, tunerId, channelId }

Test Result: ✅ Working

curl -X POST http://localhost:3000/api/stream-token \
  -H "Content-Type: application/json" \
  -H "Cookie: better-auth.session_token=<TOKEN>" \
  -d '{"tunerId": 1, "channelId": 1}'

2. GET /api/preferences/channels

  • Fetches user channel preferences (favorites, hidden)
  • Optional tunerId query parameter for filtering
  • Returns only channels with explicit preferences
  • INNER JOIN channels with user_channel_preferences

Test Result: ✅ Working (4 favorites returned)

curl -X GET "http://localhost:3000/api/preferences/channels?tunerId=1" \
  -H "Cookie: better-auth.session_token=<TOKEN>"

Code Quality

  • ✅ Lint clean (0 errors)
  • ✅ Type safe (TypeScript passes)
  • ✅ Follows existing patterns (Better-Auth, Drizzle, Next.js)
  • ✅ Comprehensive error handling (400, 401, 404, 500)
  • ✅ OpenAPI contract compliance (100%)

Authentication: Cookie-Based (By Design)

HD Homey uses Better-Auth with JWT sessions in HTTP-only cookies. This is intentional:

  • More secure for web (XSS-proof)
  • Works great for mobile (simple Cookie header)
  • Better-Auth native implementation

See: specs/013-android-app-phase2/WHY-COOKIE-AUTH.md for detailed explanation.

Phase 2 Planning Documentation ✅

Planning Documents Created (8 files, 4,160 lines)

  1. plan.md (800 lines) - Implementation strategy

    • Architecture evolution: Repository → MVVM + Hilt DI
    • 6 sub-phases, 15-21 day timeline
    • Technology stack (Retrofit, Media3, Coil, DataStore, Hilt)
  2. research.md (650 lines) - Technology research

    • AndroidX Media3 1.9.0 (ExoPlayer for HLS)
    • Retrofit 2.11.0 (type-safe HTTP)
    • Complete version catalog
  3. data-model.md (800 lines) - Entity definitions

    • Three-layer architecture: API → Domain → UI
    • Channel, ChannelPreferences, StreamToken entities
    • UI state models
  4. contracts/ (3 OpenAPI specs, 695 lines)

    • channel-api.yaml
    • stream-token-api.yaml
    • preferences-api.yaml
  5. quickstart.md (500 lines) - Manual testing guide

    • 16 test scenarios
    • ADB commands, performance metrics
  6. BACKEND-TESTING.md (347 lines) - API testing guide

    • curl commands for all scenarios
    • Postman setup
    • Test data setup
  7. WHY-COOKIE-AUTH.md (325 lines) - Architecture explanation

    • Why Cookie auth vs Bearer tokens
    • Android implementation pattern
    • Security comparison
  8. BACKEND-COMPLETE.md (316 lines) - Completion summary

Phase 1 Cleanup

  • Archived Phase 1 completion docs
  • Created comprehensive Phase 1 summary (525 lines)
  • Updated main spec to v1.3

Files Changed

New API Endpoints

apps/web/src/app/api/stream-token/route.ts               (124 lines)
apps/web/src/app/api/preferences/channels/route.ts       (105 lines)

Phase 2 Planning

specs/013-android-app-phase2/
├── plan.md                           (800 lines)
├── research.md                       (650 lines)
├── data-model.md                     (800 lines)
├── contracts/
│   ├── channel-api.yaml              (239 lines)
│   ├── stream-token-api.yaml         (202 lines)
│   └── preferences-api.yaml          (254 lines)
├── quickstart.md                     (500 lines)
├── BACKEND-TESTING.md                (347 lines)
├── WHY-COOKIE-AUTH.md                (325 lines)
├── BACKEND-COMPLETE.md               (316 lines)
└── PLANNING-COMPLETE.md              (390 lines)

Phase 1 Cleanup

specs/013-android-app-phase1/
├── PHASE1-SUMMARY.md                 (525 lines)
└── archive/                          (10 completion docs archived)

.specify/features/013-android-app.md  (updated to v1.3)

Total: 23 files changed, 8,896 lines added

Testing

Live Testing Performed ✅

  • POST /api/stream-token: Token generated successfully
  • GET /api/preferences/channels: 4 favorites returned
  • tunerId filtering: Works correctly
  • Cookie authentication: Verified working

Test Environment

  • Server: HD Homey dev server (localhost:3000)
  • User: Admin account
  • Data: 4 favorite channels (WSTMNBC, WSYR-HD, WKOFCBS, FOX68)

Next Steps After Merge

  1. Update Android Phase 2 branch: Merge main to get backend changes
  2. Generate task breakdown: Run /speckit.tasks
  3. Begin Android implementation: 3-4 weeks (15-21 days)

Related

  • Main Spec: .specify/features/013-android-app.md (v1.3)
  • Channel Favorites: SPEC-012
  • Phase 1 Summary: specs/013-android-app-phase1/PHASE1-SUMMARY.md

Checklist

  • Endpoints implemented and tested
  • Lint passes (0 errors)
  • Type checking passes
  • OpenAPI contracts followed
  • Live testing successful
  • Documentation complete
  • Architecture decisions documented
  • Phase 2 planning complete
  • Phase 1 cleanup complete

…mary

- Move all PHASE1.*-COMPLETE.md files to archive/ directory
- Create comprehensive PHASE1-SUMMARY.md consolidating all achievements
- Create specs/013-android-app-phase2/ directory for Phase 2 planning
- Branch: 013-android-app-phase2 created from main

Phase 1 achievements:
- Multi-server management (add/edit/delete)
- OAuth 2.0 device code pairing
- Professional HD Homey branding
- 86 unit tests passing (100% data layer coverage)
- Lint clean (0 errors)
- Production-ready foundation
- Update status to 'Phase 1 Complete & Merged | Phase 2 Ready'
- Version bump to 1.3
- Document Phase 1 merge details (squash merge, 323 files, +24,331 lines)
- Add Phase 1 learnings section
- Document Phase 2 architecture evolution plans (ViewModels, DataStore, Retrofit, Coil)
- Update technical stack details (Kotlinx Serialization, Truth, MockK)
- Update last updated date to 2025-12-14
- Note: Branch 013-android-app-phase2 created from main
Phase 2: Channel Browsing & Streaming
- MVVM architecture with ViewModels and Use Cases
- Retrofit for API calls, replacing raw OkHttp
- AndroidX Media3 (ExoPlayer) for HLS video playback
- DataStore replacing SharedPreferences (encrypted token storage)
- Coil for channel logo image loading
- Hilt for dependency injection

Architecture evolution:
- Introduce domain layer with Use Cases
- Add ViewModels for proper state management
- Repository pattern for data access
- JWT token refresh handling
- HMAC stream URL generation

Scope:
- Channel list screen with D-pad navigation
- Video player with Media3 ExoPlayer
- Channel favorites integration
- 5 new screens, 6 sub-phases
- Estimated: 15-21 days (3-4 weeks)

Next: Create research.md, data-model.md, contracts/, quickstart.md
Define entities for Phase 2: Channel, ChannelPreferences, StreamToken
- Three-layer architecture: API DTOs → Domain Models → UI Models
- Channel entity with sorting, filtering, favorites support
- StreamToken with HMAC authentication and expiry handling
- UI state models for ChannelList and Player screens
- DataStore preference keys for JWT and active server
- Complete mapping functions and validation rules
- Data flow diagrams from API to UI
Define OpenAPI contracts for three REST APIs:
- channel-api.yaml: GET /api/tuners/{id}/channels (existing endpoint)
- stream-token-api.yaml: POST /api/stream-token (needs implementation)
- preferences-api.yaml: GET /api/preferences/channels (needs implementation)

Each contract includes:
- Complete request/response schemas
- Authentication requirements (JWT bearer token)
- Example payloads
- Error responses (401, 404, 500)
- Implementation notes for backend

Note: stream-token and preferences APIs need backend implementation
before Phase 2 can begin.
Comprehensive manual test scenarios for Phase 2 validation:
- Channel list loading (with favorites, errors, empty states)
- D-pad navigation testing
- Video playback (basic, controls, channel switching)
- Token authentication (15-min HMAC, 7-day JWT)
- Error scenarios (server unreachable, tuner deleted, no channels)
- Performance testing (memory, cold start)
- Accessibility testing (TalkBack)

Includes:
- 16 test scenarios with expected results
- Pass/fail summary template
- ADB commands for testing
- Network simulation commands
- Performance metrics checklist
- Tester notes and recommendations section
…mmit)

Technology research for Phase 2 implementation:
- AndroidX Media3 1.9.0: ExoPlayer for HLS playback
- Retrofit 2.11.0: Type-safe HTTP client replacing OkHttp
- Coil 2.7.0: Kotlin-first image loading for channel logos
- DataStore 1.1.1: Async preferences replacing SharedPreferences
- Hilt 2.52: Dependency injection for MVVM architecture
- Kotlin Coroutines 1.10.1: Flow patterns for reactive data
- Turbine 1.1.0: Flow testing library

Includes:
- Version rationale (why these versions)
- Alternatives considered (why rejected)
- Integration examples for each library
- Complete version catalog with dependency coordinates
- Learning resources and official documentation
…tation

Comprehensive planning summary documenting:
- 5 major planning documents created (3,445 lines)
- 3 OpenAPI API contracts defined (channel, stream-token, preferences)
- Architecture evolution: Repository Pattern → MVVM + Hilt DI
- 7 new technologies researched (Retrofit, Media3, Coil, DataStore, etc.)
- 16 manual test scenarios defined
- 15-21 day implementation timeline estimated

Key findings:
- Backend needs 2 new endpoints: POST /api/stream-token, GET /api/preferences/channels
- Phase 2 requires production-ready architecture (MVVM, DI, ExoPlayer)
- High-risk items: HLS playback complexity, token expiry handling
- Real device testing essential (emulator video performance poor)

Next steps:
1. Implement missing backend endpoints (2-4 hours)
2. Run /speckit.tasks to generate task breakdown
3. Begin 3-4 week Android implementation

Status: ✅ PLANNING COMPLETE - Ready for backend work
Add two new REST API endpoints required for Android Phase 2:

1. POST /api/stream-token
   - Generate short-lived HMAC-SHA256 tokens for HLS streaming
   - Accept tunerId and channelId in request body
   - Return token with expiry timestamp (configurable, default 12 hours)
   - Validate JWT authentication
   - Verify tuner and channel exist and are not deleted
   - Follows OpenAPI contract: specs/013-android-app-phase2/contracts/stream-token-api.yaml

2. GET /api/preferences/channels
   - Fetch user channel preferences (favorites, hidden)
   - Optional tunerId query parameter for filtering
   - Only returns channels with explicit preferences set
   - INNER JOIN channels with user_channel_preferences
   - Returns channelId, tunerId, guideNumber, guideName, isFavorite, isHidden, updatedAt
   - Follows OpenAPI contract: specs/013-android-app-phase2/contracts/preferences-api.yaml

Implementation details:
- Uses Better-Auth JWT session authentication
- Follows existing HD Homey API patterns (zod validation, error handling)
- Proper error responses: 400 (bad request), 401 (unauthorized), 404 (not found), 500 (server error)
- Lint clean and type safe

Testing:
- Lint: ✅ passes
- Type check: ✅ passes
- Manual testing needed: Use Postman/curl (see specs/013-android-app-phase2/quickstart.md)

Related: SPEC-013 (Android App Phase 2), SPEC-012 (Channel Favorites)
Create detailed testing guide for stream-token and preferences APIs:
- curl commands for all test scenarios (success + error cases)
- How to obtain JWT tokens (browser extraction + device pairing)
- Postman collection setup instructions
- Test data setup (SQL + web UI)
- Verification checklist for both endpoints
- Common issues and solutions
- Response examples for all cases

Test scenarios covered:
- Valid requests (200)
- Missing authentication (401)
- Invalid request body (400)
- Resource not found (404)
- Empty results handling

Enables developers to validate backend implementation before Android Phase 2.
Better-Auth uses session cookies, not Bearer tokens:
- Change all examples from 'Authorization: Bearer' to 'Cookie: better-auth.session_token='
- Update terminology from 'JWT token' to 'session token'
- All test commands now use correct Cookie header

Verified working:
- POST /api/stream-token ✅ Returns valid HMAC token
- GET /api/preferences/channels ✅ Returns user's 4 favorite channels
- tunerId filter works correctly
Comprehensive completion summary documenting:
- Both endpoints implemented and tested successfully
- Live testing results with actual data (4 favorite channels returned)
- Authentication method clarified (Cookie vs Bearer token)
- Code quality verified (lint ✅, type check ✅)
- OpenAPI contract compliance confirmed
- Android implementation notes (Retrofit interceptor pattern)

Test Results:
- POST /api/stream-token ✅ Returns valid HMAC token
- GET /api/preferences/channels ✅ Returns 4 favorites (WSTMNBC, WSYR-HD, WKOFCBS, FOX68)
- tunerId filtering ✅ Works correctly

Key Discovery:
- Better-Auth uses Cookie header, not Authorization Bearer
- Android app needs Retrofit interceptor to add Cookie header

Next Steps:
1. Merge to main
2. Update Android Phase 2 branch
3. Run /speckit.tasks to generate task breakdown
4. Begin 3-4 week Android implementation

Status: ✅ BACKEND COMPLETE - READY TO MERGE
Comprehensive explanation of HD Homey's authentication architecture:
- Better-Auth uses JWT sessions in HTTP-only cookies
- Cookie auth is more secure for web (XSS-proof)
- Cookie auth works perfectly for mobile (OkHttp interceptor)
- Bearer token support would require manual JWT validation
- Phase 2 plan already includes AuthInterceptor implementation

Key findings:
- Better-Auth is cookie-first by design (not easily adaptable to Bearer tokens)
- Mobile apps should send: Cookie: better-auth.session_token=<TOKEN>
- This is already documented in Phase 2 planning documents

Comparison table shows Cookie auth advantages:
- More secure (HTTP-only)
- Less code to maintain (Better-Auth handles it)
- Equally easy for mobile (simple interceptor pattern)

Alternative approach documented (manual JWT validation) but NOT recommended.

Status: No changes needed - architecture is sound
@github-actions
Copy link

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@shaunburdick shaunburdick merged commit 342bd40 into main Dec 14, 2025
13 checks passed
shaunburdick added a commit that referenced this pull request Dec 14, 2025
Create cleanup documentation:
- BRANCH-CLEANUP.md: Guide for removing merged branches (PR #28, etc.)
- specs/013-android-app-phase2/START-PROMPT.md: Copy-paste prompt for starting Phase 2

Cleanup targets:
- Local: 013-android-app-phase2, 013-android-app-phase2-backend (merged in PR #28)
- Local: 010-user-invitations, 011-github-pages-docs (merged previously)
- Local: feature/005-video-transcoding (merged in PR #17)
- Remote: Multiple merged branches via GitHub UI

Start prompt provides two approaches:
1. Single task (T001) - Step by step
2. Batch tasks (T001-T007) - Add all dependencies at once

Phase 2 implementation ready to begin!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants