Skip to content

Releases: PGAN-Dev/PoracleWeb.NET

v2.8.0 — Compose simplification, favicon, invasion fixes

14 Apr 17:58
038c7e1

Choose a tag to compare

Changed

  • Docker compose is now shipped as docker-compose.yml.example (#228): following the .env / .env.example pattern, docker-compose.yml is now gitignored and users copy the example on first install. Upstream tweaks to the example no longer clobber local customizations. The compose file also switched to env_file: .env instead of enumerating every variable under environment:, shrinking it by ~35 lines and making .env the single source of configuration truth. The default image is now ghcr.io/pgan-dev/poracleweb.net:latest (pull) to match the README Quick Start; the local-build and build: alternatives remain as commented options.

    Upgrade (existing self-hosted users):

    cp docker-compose.yml docker-compose.yml.bak   # back up any local edits first
    git pull
    cp docker-compose.yml.example docker-compose.yml
    # re-apply any customizations from docker-compose.yml.bak (prefer docker-compose.override.yml for future edits)
    docker compose up -d --force-recreate

    No .env changes are required — existing .env files remain compatible.

    Two things to know after upgrade:

    • Existing users will be logged out once. JWT issuer/audience defaults changed from Pgan.PoracleWebNet / Pgan.PoracleWebNet.App to PoracleWeb / PoracleWeb.App. Previously issued tokens fail validation and users re-login via Discord/Telegram — no data loss, just a single sign-in prompt. To keep the old values, set JWT_ISSUER=Pgan.PoracleWebNet and JWT_AUDIENCE=Pgan.PoracleWebNet.App in .env before restarting.
    • Default image source changed. The example compose now pulls ghcr.io/pgan-dev/poracleweb.net:latest. If you previously relied on a locally built poracleweb.net:latest, uncomment the local-build alternative in your docker-compose.yml before running docker compose up -d or you'll pull the published image instead.

Added

  • Admin-configurable favicon (#218): new favicon_url site setting under the Branding group in Admin → Settings. Admins can point to any hosted image (.ico, .png, .svg; 32×32 square recommended); leaving it empty falls back to the bundled default. Includes a live 32×32 preview next to the input and an inline warning that browsers aggressively cache favicons — users must clear their browser cache or hard-refresh (Ctrl+F5 / Cmd+Shift+R) to see the new icon. Applied at runtime by mutating the <link rel="icon"> href via an Angular effect, mirroring the existing custom-title pattern. Exposed on the public settings endpoint so it loads pre-auth.
  • Optional JWT_ISSUER / JWT_AUDIENCE env vars (#228): documented in .env.example with sensible defaults (PoracleWeb and PoracleWeb.App) applied by Program.cs when unset, so existing users don't need to add them. Override only if you need distinct token identities across deployments.
  • Giovanni quick pick (#221): split out while fixing the Rocket Leaders pick. New invasion-giovanni default quick pick tracks Giovanni encounters (gruntType=giovanni). Kept separate from "Rocket Leaders" because Giovanni spawns from the Super Rocket Radar only, while Sierra/Cliff/Arlo come from standard Rocket Radars — users typically want them on distinct alert profiles.

Fixed

  • Invasion grunt icon now reflects the rule's gender filter (#224): for the 18 typed grunts (bug, fire, water, etc.), rules filtered by Male or Female now render the actual gendered grunt artwork from PogoAssets (uicons/invasion/<character_id>.png) by mapping (grunt_type, gender) to the Niantic InvasionCharacter enum — e.g. Water + Female → invasion 38, Water + Male → 39. "Any" gender keeps the existing Pokémon-type badge. The edit dialog preview updates live via a toSignal on the gender form control.
  • Editing an invasion alarm's gender created a duplicate row (#224): PoracleNG dedups invasion tracking by the natural key (grunt_type, gender), so PUT-ing the row with a new gender caused a fresh insert instead of updating the referenced uid — leaving the original row as a stale duplicate. InvasionService.UpdateAsync now detects the insert response and deletes the old uid, tolerating network/timeout failures on the cleanup delete with a Warning log.
  • i18n: invasion grunt type labels (#223): hardcoded English grunt type names in invasion.constants.ts (DISPLAY_NAMES) and invasion-add-dialog.component.ts (GRUNT_TYPES[].name) bypassed the i18n system, so users on non-English locales still saw "Mixed Grunt", "Shadow", "Cliff", "Fire", etc. in English. Added INVASIONS.GRUNT_TYPES.* (26 keys), INVASIONS.EVENT_TYPES.* (3 keys), and INVASIONS.GENDER_SUFFIX_MALE/FEMALE to all 11 locale files. Replaced DISPLAY_NAMES with GRUNT_DISPLAY_KEYS + getGruntDisplayKey() and added a getGruntDisplayName(gruntType, gender, translate) composer that appends a translated (Male)/(Female) suffix for the gender-fixed grunts (mixed/decoy). Updated add/edit dialog, invasion list, and profile-overview consumers.
  • Mobile: Pokemon list search/filter bar no longer leaves a 56px gap above itself when sticky. top changed from 56px to 0 since mat-sidenav-content is the scroll container and already sits below the app toolbar. Tightened the mobile (max-width: 599px) layout so the search field, quick-filter pills, and meta row stack cleanly at 390px viewports. (#213)
  • Mixed grunt gender variants (#221): the Mixed entry in the add-invasion dialog was a single checkbox with one icon, hiding the fact that Mixed grunts have male/female variants with distinct invasion character IDs (Male 4 — starter line, Female 5 — Snorlax line). The dialog now offers separate Male/Female checkboxes, and getGruntIconUrl / getDisplayName use the alarm's gender to render the correct icon and a "(Male)"/"(Female)" suffix in the list and edit views. Decoy grunts default to invasion ID 46 (female) since the male variant (45) exists in the masterfile but does not spawn in-game.
  • "Rocket Leaders" quick pick subscribed users to the wrong grunts (#221): the invasion-leader pick sent gruntType=mixed, which in PoracleNG is the untyped CHARACTER_GRUNT_MALE/FEMALE grunt, not Sierra/Cliff/Arlo. Applying the pick now fans out to three invasion alarms with the real leader grunt types (cliff, arlo, sierra) via a single bulk-create. Users who previously applied the broken pick should unapply and re-apply it to replace their stale mixed alarms. Added QuickPickDefaultsTests to assert default invasion picks use valid PoracleNG grunt_type values and to regression-guard against mixed being used for leaders.
  • Invasion grunt icons and labels (#216): mixed grunts rendered as "Rocket Leader" with the Cliff icon (invasion ID 41 = EXECUTIVE_CLIFF), and decoy grunts rendered with the Electric icon (invasion ID 50 = ELECTRIC_GRUNT_MALE). Corrected both to their real Niantic InvasionCharacter IDs — mixed → 4 (untyped grunt), decoy → 46 (female decoy; the male variant 45 exists in the masterfile but does not spawn in-game). Added missing grunt types surfaced by PoracleNG: darkness (Shadow) and the Rocket Leaders cliff/arlo/sierra. Also replaced the empty-string fallback in getGruntIconUrl() with a generic unknown-grunt icon so an unmapped grunt_type renders a valid placeholder instead of a broken image. Updated both invasion.constants.ts and the add-invasion dialog. See the "Mixed grunt gender variants" entry above for the related add-dialog UX work.

v2.7.0 — i18n completion, release automation, dependabot

13 Apr 04:38
e9a588c

Choose a tag to compare

Highlights

Added

  • Three-channel Docker release process (:latest, :beta, :pr-<n>) — public testers can opt into pre-release builds before an official release is cut. Nightly prune workflow keeps the registry tidy. See TESTING.md.
  • Automated PR labeling & release-notes generationpr-labeler.yml applies Conventional-Commit labels from branch prefix or PR title; .github/release.yml groups labeled PRs for GitHub's auto-generated notes.
  • Dependabot — weekly grouped updates for NuGet, npm, GitHub Actions, and Docker base images. Angular/Material majors pinned for manual coordination.
  • Dependabot auto-merge.github/workflows/dependabot-auto-merge.yml auto-approves and queues patch bumps, grouped bundles, and GH Actions minor bumps (gated on CI).

Fixed

  • i18n raw-token rendering: QUESTS.CONFIRM_DELETE_SELECTED / INVASIONS.CONFIRM_DELETE_SELECTED no longer render as literal keys on the bulk-delete dialog. (#209)
  • i18n 277-key coverage gap across 10 non-English locales — every missing key now has a native translation (2,770 translations total: fr, de, es, nl, it, pt, pt-BR, pl, da, sv). Native-speaker review welcome in discussion #211.
  • Documentation branding: 88 remaining bare PoracleWeb references replaced with PoracleWeb.NET across 16 docs/ files.

Changed

  • Angular group bumped (13 package updates).
  • Microsoft group bumped (10 package updates).
  • Various CI action majors (checkout, setup-dotnet, login-action, metadata-action, setup-buildx-action, typescript/angular-eslint/dependabot-config housekeeping).

Full changelog: v2.6.0...v2.7.0

v2.6.0 — Security hardening & Poracle server management removal

12 Apr 20:08

Choose a tag to compare

Highlights

🔒 Security hardening

  • Removed the Poracle server management feature (#176, PR #181) — eliminates the only shell-command-execution code path (System.Diagnostics.Process + SSH). Closes command-injection surface in RestartCommand/GroupMapPath config values and removes the need to mount SSH keys in the container. openssh-client package removed from the Docker image.
  • Persisted ASP.NET Core DataProtection keys to filesystem (#174, PR #179) — keys now survive container restarts, eliminates ephemeral-key startup warnings.

✨ New

  • Configurable login buttons (#172, PR #177) — show/hide Discord and Telegram login based on .env config with admin-disabled state.

🔧 Changed

  • Replaced AutoMapper with manual mapping extension methods (#173, PR #178) — removed the commercial-license dependency. All mappings now use static extension methods in Core.Mappings. No API contract or behavioral changes.

🎨 Fixed

  • Consistent 'PoracleWeb.NET' branding (#175, PR #180).

Upgrade notes

Backwards compatible

Existing .env files containing PORACLE_SERVER_* or SSH_KEY_PATH vars are silently ignored after upgrade — no .env changes required for the app to keep running.

Recommended ops actions

Since the SSH-based server restart feature was removed:

  • Delete ./data/ssh_key from the Docker host
  • Rotate the SSH keys previously used for PoracleJS server access
  • Remove the PoracleWeb public key from ~/.ssh/authorized_keys on each PoracleJS server
  • Remove firewall rules opened for PoracleWeb → PoracleJS SSH access (port 22)

Full changelog: v2.5.0...v2.6.0

v2.5.0

12 Apr 06:32

Choose a tag to compare

What's New

Added

  • Signup page redirect for non-registered users (#168, PR #171): New admin-configurable signup_url site setting (Settings > Analytics & Links) displays a green "Sign Up" button on the login page. When a non-registered user attempts to log in and receives a user_not_registered or missing_required_role error, the signup button directs them to the configured registration page. Button hidden when no URL is configured.
  • Internationalized ~45 hardcoded UI strings (PR #171): Extracted hardcoded English strings into i18n translation keys across all 11 supported languages covering auth errors, HTTP error toasts, test alert messages, admin settings, fort changes, max battles, and template condition labels.

Fixed

  • Alarms landing on wrong profile after PoracleNG auto-switches via active_hours scheduler (#167, PR #170): JWT profile desync detected and auto-corrected via refreshed token on /api/auth/me.

Changed

  • Extracted IJwtService: Consolidated JWT token generation from 4 independent implementations into a shared singleton.

Full Changelog: v2.4.1...v2.5.0

v2.4.1

12 Apr 01:39
55b22c9

Choose a tag to compare

Fixed

  • Test alert DMs now satisfy the alarm's own filter (#165): Clicking Test Alert on a "Great League rank 1-1 Tinkaton" filter previously delivered a DM with IVs 1/14/14 at L25.5 — values that didn't satisfy the filter being tested — because TestAlertService.BuildPokemonWebhook hardcoded IVs to 15/15/15, level to 35, CP to 2500, and shipped literal pvp_rankings_great_league/_ultra_league arrays with rank: 1 regardless of the alarm's configured filter. PoracleNG's render pipeline then faithfully enriched the lies. Rewrote the monolithic builder as six ITestPayloadBuilder implementations under Core.Services/TestAlerts/, each reading the alarm's own filter columns and emitting matching raw webhook values aligned to the live PGAN DTS template variable set. Ported gohbem's PVP rank calculator (Core.Services/Pvp/PvpRankCalculator + 109-entry CpMultiplierTable) to resolve PVP-filter alarms to real rank-matching IV/level/CP combos — GL rank 1 Tinkaton now renders as 13/15/15 L49.5 CP 1498 with a matching single-entry PVP rank panel. Rank tables cached per (pokemonId, form, league) via IPvpRankService + IMemoryCache with no TTL (~16 KB per species, O(1) after the first ~1 ms sweep). Extended MasterDataService to expose per-species baseAttack/baseDefense/baseStamina from the WatWowMap Masterfile. Every builder honors the full filter field set: IV floors/ceilings, min_iv/max_iv, min_level/max_level, min_cp/max_cp, form, gender, size, and league-aware PVP rank windows. Also aligned raid/egg wire fields to the live PGAN DTS convention (name+url, not gym_name/gym_url), merged egg into the raid wire type (pokemon_id=0), fixed a latent quest-webhook template field collision with the in-game quest template key, and corrected invasion field names (name/incident_grunt_type/incident_expiration). 24 new payload assertion tests pin the filter-to-wire contract plus 19 PVP algorithm property tests. (PR #166)
  • custom geofence toggle not persisting (#163) (PR #164)
  • Custom geofence toggle not persisting (#163): Activating/deactivating a user-drawn geofence via the Geofences page toggle appeared to succeed but silently reverted on the next page load. Root cause: PoracleNG's POST /api/humans/{id}/setAreas handler intersects the submitted area list against fences where userSelectable=true (for non-admin users), and user geofences are served from PoracleWeb's feed with userSelectable=false so they were silently stripped. Regression introduced in v2.0.0 by the PoracleNG API proxy migration, which routed user geofence area writes through SetAreasAsync instead of the pre-migration direct-DB path. Introduced IUserAreaDualWriter — a tiny atomic-write abstraction over PoracleContext that commits both humans.area and the active profiles.area in a single SaveChangesAsync call (EF Core implicit transaction = the two writes cannot drift). UserGeofenceService.Create/Delete/AddToProfile/RemoveFromProfile/AdminDelete now delegate to the writer instead of making separate IHumanRepository + IProfileRepository calls. AddToProfile and RemoveFromProfile also call ReloadGeofencesSafeAsync manually because the direct-DB path skips PoracleNG's HandleSetAreas terminal reload. Also fixed a related bug where saving on the Areas page would silently strip user geofences the user had activated: AreaController.UpdateAreas now calls IUserGeofenceService.PreserveOwnedAreasInHumanAsync after SetAreasAsync, which hands off to the writer's bulk AddAreasToActiveProfileAsync method (one DB round-trip regardless of geofence count). This is a temporary workaround — the proper fix is a new PoracleNG API endpoint that bypasses the userSelectable filter for trusted callers. See docs/poracleng-enhancement-requests.md (trusted-set-areas gap). All affected sites are tagged with HACK: trusted-set-areas comments — when PoracleNG ships the fix, grep -rn "HACK: trusted-set-areas" --include="*.cs" will list every site that needs to be reverted.

v2.4.0 — Multi-language / i18n Support

09 Apr 14:39

Choose a tag to compare

What's New

Full internationalization support with 11 UI languages matching the original PoracleWeb PHP: English, French, German, Spanish, Dutch, Italian, Portuguese, Brazilian Portuguese, Polish, Danish, Swedish.

Highlights

  • Runtime language switching — change language instantly from the user menu, no page reload
  • Browser auto-detection — first visit auto-detects preferred language
  • SVG country flags — crisp flag icons in the language selector
  • Admin controlallowed_languages site setting restricts available languages
  • 12,331 translated strings — 1,121 keys per language across every page, dialog, tooltip, and snackbar
  • Help guide fully translated — all 17 sections with rich HTML content
  • Fallback detection — amber "English" chip on untranslated sections
  • Shared pipes i18n — league, gender, lure, team, distance pipes use translated output
  • Admin settings i18n — 106 setting labels and descriptions translatable
  • I18nService tests — 11 unit tests for the core service
  • MkDocs docs — i18n feature page + custom landing page

Upgrade Notes

  • No database changes required
  • New npm dependency: @ngx-translate/core v17, @ngx-translate/http-loader v17
  • New assets: src/assets/i18n/*.json (11 translation files), src/assets/flags/*.svg (11 flag icons)
  • Optional: Set allowed_languages in Admin → Settings → Features to restrict available languages

Full Changelog: v2.3.0...v2.4.0

v2.3.0

08 Apr 18:08

Choose a tag to compare

What's New

Added

  • Area overview map on dashboard: Non-interactive Leaflet mini-map showing selected areas as color-coded polygons. Lazy-loaded via @defer(on viewport) with zero additional API calls. Click navigates to the full Areas page. (#129, PR #160)
  • Profile active hours / schedule management UI (#158, PR #159)
    • View and edit active hours on user profiles for automatic profile switching
    • Schedule editor dialog with day picker, time picker, and weekly preview
    • Amber schedule pills on profile cards showing activation times
    • Location warning when profile has 0,0 coordinates (causes timezone bug in PoracleNG scheduler)
    • Server-side validation (day 1-7, hours 0-23, mins 0-59, max 28 entries)

Removed

  • Unused ProfileListComponent (was never routed)

Full Changelog: v2.2.0...v2.3.0

v2.2.0

07 Apr 19:32

Choose a tag to compare

Added

  • Max Battle (Dynamax) tracking alarms: Full-stack alarm module for Dynamax and Gigantamax Max Battle tracking at Power Spots (#118, PR #137)
  • Fort Change tracking alarms: Monitor pokestop and gym changes — name changes, relocations, image updates, removals, and new forts (#119, PR #135)
  • Unified Profiles page with alarm overview: View all alarms across all profiles with backup/restore, duplicate detection, and profile name uniqueness (#127, PR #147)
  • Profile duplicate: Clone a profile with all alarms, areas, and location in one operation (#120, PR #145)
  • Send test alert / notification preview: Test button on every alarm card sends a simulated notification through PoracleNG (#122, PR #148)
  • Weather display at user location: Dashboard shows current in-game weather with boosted type chips and per-area weather icons (#128, PR #149)
  • Pokemon availability indicators from Golbat: Pokemon selector shows which species are currently spawning with "Live > Spawning" filter (#133, PR #154)
  • GeoJSON geofence export and import: Export/import geofences as standard GeoJSON files with drag-and-drop upload and preview (#130, PR #155)
  • Max Battles quick pick support (#140, PR #143)
  • Login method gating: enable_discord and enable_telegram settings gate login methods (#117, PR #136)
  • Dedicated Discord settings section in admin page (PR #116)

Fixed

  • Quick pick "all invasions" fails with 400 (#139, PR #141)
  • Raid card shows 9000 stars for level 9000 (#138, PR #144)
  • Quick pick raid level override (PR #144)
  • Profile rename not saving (PR #147)
  • Quest test alerts missing static maps (PR #153)

Full Changelog: v2.1.3...v2.2.0

v2.1.3

04 Apr 06:36

Choose a tag to compare

Fixed

  • Custom geofences lost when toggling areas: syncSelectedFromAreas() was overwriting selected areas with only predefined names, silently dropping custom geofence subscriptions — toggling any predefined area checkbox then saving would deactivate custom geofences (#109, PR #113)

Full Changelog: v2.1.2...v2.1.3

v2.1.2

04 Apr 05:36

Choose a tag to compare

Fixed

  • Areas page layout: Remove max-width: 800px constraint for consistent full-width layout matching My Geofences page (#107, PR #110)
  • Site title after OAuth redirect: Load site settings after Discord callback stores JWT token — title was stuck on default "DM Alerts" because loadOnce() fired before the token was available (#106, PR #111)
  • Webhook admin actions broken: Move user ID from path to query parameter for 8 admin endpoints — webhook IDs are URLs with slashes that broke ASP.NET Core {id} route matching (#105, PR #112)

Full Changelog: v2.1.1...v2.1.2