Files
server/AGENTS.md
2026-02-13 14:16:52 +01:00

12 KiB
Raw Blame History

Repository Guidelines

Snapshot & Stack

  • Java Spring Boot 3.2 service that backs the Imgfloat livestream overlays, admin UI, and dashboard.
  • Uses Spring MVC controllers, WebSocket/STOMP broadcasts (SimpMessagingTemplate), OAuth2/Twitch authentication, and scheduled/async services (@EnableScheduling, @EnableAsync in ImgfloatApplication).
  • Media-heavy assets are stored on disk (assets/, previews/), processed with ffmpeg/ffprobe, and surfaced through static/js / Thymeleaf templates under src/main/resources.

Architecture & Modules

  • src/main/java/dev/kruhlmann/imgfloat/config: Spring configuration beans (upload limits, security overrides, asset storage wiring).
  • controller: REST + view controllers keep endpoints thin and delegate work to services and repositories.
  • service: business logic (asset management, marketplace seeds, git info, Twitch emote syncing, audit logging, cleanup, media optimization, etc.). service.media contains ffmpeg helpers and media detection.
  • repository: Spring Data JPA interfaces for the Imgfloat DB (Asset, Channel, ScriptAsset, etc.) and a separate audit DB under repository.audit.
  • model: db packages mirror schema entities; api.request/response hold DTOs used by controllers.
  • templates: Thymeleaf views (admin.html, broadcast.html, dashboard.html, etc.).
  • static: frontend JavaScript modules (static/js/admin, static/js/broadcast/*, static/js/customAssets.js, etc.), CSS, icons, and broadcast worker scripts. Keep new assets next to the feature they support.
  • src/main/resources/db/migration and db/audit: Flyway migration scripts that must stay in sync with the SQLite schemas referenced by IMGFLOAT_DB_PATH and IMGFLOAT_AUDIT_DB_PATH.

Environment & Configuration

  • .env files are only loaded when you run make run; shelling mvn spring-boot:run directly requires manually exporting each variable.

  • Required environment variables (set them via .env locally or through your deployment tooling):

    Variable Purpose
    IMGFLOAT_ASSETS_PATH Base filesystem directory for uploaded assets. AssetStorageService sanitizes broadcaster segments under this path.
    IMGFLOAT_PREVIEWS_PATH Where generated previews (PNG thumbnails) go.
    IMGFLOAT_DB_PATH SQLite file used by the main Flyway-managed schema (db/migration).
    IMGFLOAT_AUDIT_DB_PATH SQLite file for audit logs (db/audit) and session storage.
    IMGFLOAT_INITIAL_TWITCH_USERNAME_SYSADMIN Twitch login that becomes the initial sysadmin and can manage all channels.
    IMGFLOAT_GITHUB_CLIENT_OWNER/REPO/VERSION GitHub release coordinates used by GithubReleaseService to build download links for the client bundle.
    IMGFLOAT_TOKEN_ENCRYPTION_KEY Base64/Base64URL-encoded 32-byte key used by Spring Security to encrypt OAuth tokens at rest.
    SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE / MAX_REQUEST_SIZE Control upload limits (defaults to 10MB in Makefile, also read by UploadLimitsConfig which exposes uploadLimitBytes to controllers/services).
    TWITCH_CLIENT_ID & TWITCH_CLIENT_SECRET Used by Spring Securitys OAuth2 client registration in application.yml.
  • Optional/operational variables:

    Variable Purpose
    IMGFLOAT_COMMIT_URL_PREFIX Enables the commit chip in the UI (GitInfoService) when paired with git-commit-id-plugin.
    IMGFLOAT_DOCS_URL Base URL for documentation links rendered in templates.
    IMGFLOAT_IS_STAGING Set to 1 to surface a staging banner across non-broadcast pages. Defaults to 0.
    IMGFLOAT_MARKETPLACE_SCRIPTS_PATH Directory containing marketplace seed directories (MarketplaceScriptSeedLoader reads metadata, source.js, logo, attachments). doc/marketplace-scripts holds examples.
    IMGFLOAT_SYSADMIN_CHANNEL_ACCESS_ENABLED Toggle to let sysadmins manage every channel without being added as an admin.
    TWITCH_REDIRECT_URI Overrides the default redirect URI for OAuth ({baseUrl}/login/oauth2/code/twitch).
    IMGFLOAT_TOKEN_ENCRYPTION_PREVIOUS_KEYS Comma-delimited base64 keys to decrypt tokens created before rotating IMGFLOAT_TOKEN_ENCRYPTION_KEY.
  • AssetStorageService will fall back to system temp dirs (java.io.tmpdir/imgfloat-assets & -previews) if IMGFLOAT_ASSETS_PATH/PREVIEWS_PATH are unset, but storing data on persistent storage is required for production.

  • UploadLimitsConfig defaults to 50MB/100MB for tests if the environment properties are absent; production should honor the spring.servlet.multipart.* values you expose.

Build, Run, & Watch

  • make build / mvn compile: compile the server.
  • make run: sources .env (if present) and runs mvn spring-boot:run. Use this for local dev; hot reload works via spring-devtools.
  • make watch: compiles continuously using entr (sleep loop watches src/main). Requires entr installed and you must refresh the browser manually after the compile succeeds.
  • make test / mvn test: run the JUnit 5 + Mockito suite (including integration tests that spin up the Spring context). Run this before pushing changes that touch controllers, services, or persistence logic.
  • make package / mvn clean package: clean build that packages the runnable JAR.
  • springdoc-openapi is on the classpath; the automated Swagger UI can be helpful for understanding the available REST endpoints.

Database & Persistence

  • The main SQLite DB (IMGFLOAT_DB_PATH) holds channel, user, asset, marketplace, and settings tables. Flyway (configured in application.yml) runs migrations from classpath:db/migration. Dont bypass these migration scripts when updating schemas.
  • Audit logs live in the separate IMGFLOAT_AUDIT_DB_PATH with migrations under src/main/resources/db/audit. The audit DB also stores Spring Session tables; spring.session.jdbc.initialize-schema is set to never, so the Flyway scripts must include the session table definitions.
  • AuditLogService sanitizes log entries before persisting them and is used by controllers such as AuditLogApiController and AccountService.

Media & Asset Handling

  • ChannelDirectoryService handles uploads. It enforces uploadLimitBytes (derived from spring.servlet.multipart.max-file-size), normalizes broadcaster names, and records audit events via AuditLogService.
  • Uploaded assets go through MediaDetectionService, MediaOptimizationService, and AssetStorageService which writes to IMGFLOAT_ASSETS_PATH. Previews (PNGs) are written to IMGFLOAT_PREVIEWS_PATH.
  • AssetStorageService sanitizes broadcaster segments (sanitizeUserSegment) to avoid traversal and auto-creates directories. When deleting, AssetCleanupService runs asynchronously after startup to remove orphan files that are not referenced by any DB record.
  • Media processing uses ffmpeg/ffprobe via FfmpegService. Make sure those binaries are available on the system; otherwise video/preview transcodes and APNG → GIF conversions will fail with warnings logged from FfmpegService.

Marketplace Scripts & Allowed Domains

  • Marketplace seeds live under the path configured by IMGFLOAT_MARKETPLACE_SCRIPTS_PATH. Each subfolder is a listing identifier and must contain metadata.json and source.js. Optional files: logo.png (renders as the marketplace badge) and attachments/ for extra files (filenames must be unique per script).
  • metadata.json combines name, optional description, optional broadcaster, and optional allowedDomains. Allowed domains control the fetch sandbox in the broadcast worker and are normalized via ChannelDirectoryService.normalizeAllowedDomains. Valid entries are hostname or hostname+port (regex ^[a-z0-9.-]+(?::[0-9]{1,5})?$), de-duplicated, lower-cased, and capped at 32 entries per script.
  • Seeds are cached at startup; MarketplaceScriptSeedLoader exposes listEntriesForQuery and findById so the frontend can show the marketplace catalog without hitting Twitch/SevenTV endpoints.
  • Example scripts are shipped under doc/marketplace-scripts/.

Security, Auth, & Tokens

  • Spring Security OAuth2 login is configured in application.yml under spring.security.oauth2.client. Twitch is the only configured provider; scopes include user:read:email and moderation:read.
  • OAuth tokens are encrypted using IMGFLOAT_TOKEN_ENCRYPTION_KEY; rotate keys by setting IMGFLOAT_TOKEN_ENCRYPTION_PREVIOUS_KEYS to a comma list of old keys (oldest last) before swapping in a new IMGFLOAT_TOKEN_ENCRYPTION_KEY.
  • IMGFLOAT_INITIAL_TWITCH_USERNAME_SYSADMIN seeds the first sysadmin; subsequent sysadmins can be managed via the UI or API. To allow sysadmins to hop between channels without being channel admins, set IMGFLOAT_SYSADMIN_CHANNEL_ACCESS_ENABLED=true.
  • GitInfoService will expose a commit link if IMGFLOAT_COMMIT_URL_PREFIX is configured and git.properties is present (generated by the git-commit-id-plugin), otherwise it falls back to running git directly.
  • GithubReleaseService fails fast when IMGFLOAT_GITHUB_CLIENT_OWNER, IMGFLOAT_GITHUB_CLIENT_REPO, or IMGFLOAT_GITHUB_CLIENT_VERSION are missing; these powers the download link in the UI.

Frontend Notes

  • Broadcast client code lives in src/main/resources/static/js/broadcast/ (renderer, workers, runtime helpers). When editing overlay scripts, keep worker changes in script-worker.js and keep main page logic in renderer.js.
  • Admin/dashboard JS modules (customAssets.js, settings.js, etc.) are plain ES modules bundled through Thymeleaf templates, so keep related CSS/HTML under static/css and templates.
  • Templates render dynamic data via controllers such as ViewController, which also injects uploadLimitBytes, version info (VersionService), and feature flags (staging banner, docs URL, commit chip wrapped in GitInfoService/GithubReleaseService values).

Testing & Validation

  • Tests are under src/test/java/dev/kruhlmann/imgfloat. Controller integration tests (e.g., ChannelApiIntegrationTest) boot up the application context—mock external services carefully or rely on the in-memory SQLite test DB created from the Flyway scripts.
  • Service unit tests (e.g., ChannelDirectoryServiceTest) cover asset normalization, allowed domain semantics, and marketplace seed behavior. Add targeted tests for new service logic, API validations, or asset handling (uploads, attachments, downloads).
  • Run make test before shipping changes; it also generates JaCoCo reports via the Maven plugin.

Coding Style & Contributions

  • Java code uses 4-space indentation, UpperCamelCase for types, lowerCamelCase for fields/methods, and UPPER_SNAKE_CASE for constants. DTOs often use records when immutability is feasible (ScriptMarketplaceEntry, MarketplaceScriptSeedLoader.SeedScript, etc.).
  • Prefer constructor injection for Spring components. Controllers should remain thin and delegate to service-layer beans; services orchestrate repositories, asset storage, storage cleanup, Git/Twitch helpers, and messaging (websockets/events).
  • Keep assets close to their feature (e.g., static/js/broadcast/ for overlay code, templates/ for the Thymeleaf view referencing that script).
  • Avoid path traversal by relying on existing sanitizers (AssetStorageService.sanitizeUserSegment). When adding new file paths, reuse safeJoin/sanitizeUserSegment patterns.
  • When syncing marketplace favorites or script attachments, obey ChannelDirectoryService.loadScriptAttachments semantics—attachments are stored in script_asset_attachment records and are cleaned up when orphaned.

Operational Tips

  • AssetCleanupService runs asynchronously once per startup (after ApplicationReadyEvent) and purges disk files whose IDs are not referenced by any DB row; do not rely on manual cleanup unless debugging.
  • VersionService looks for META-INF/maven/dev.kruhlmann/imgfloat/pom.properties first, falls back to parsing pom.xml (useful when running from source), and throws if no version is available—keep your pom.version accurate for release builds.
  • EmoteSyncScheduler, SevenTvEmoteService, TwitchEmoteService, and TwitchAppAccessTokenService orchestrate Twitch/7TV emote catalogs and should be aware of scheduling constraints if you modify emote ingestion.
  • Static files, marketplace metadata, and assets are best tested locally by running make run with the appropriate env variables and by refreshing the admin/broadcast UI manually.