RES-2054: Group Tags - Network Coordinator Management#829
Merged
Conversation
- Add network_id column to group_tags table with FK to networks
- Add GroupTags model scopes: global(), forNetwork(), availableForNetwork()
- Add Network model tags() relationship and availableTags() method
- Add GET/POST/DELETE /api/v2/networks/{id}/tags endpoints
- Add tag filter param to networks/{id}/groups, events, and stats
- Allow Network Coordinators to update tags on groups they coordinate
- Add 11 new tests for tag functionality
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add canEditTags prop to GroupAddEdit/GroupAddEditPage for NC tag access - Group tags by network name in multiselect (Global first, then alpha) - Filter listTagsv2 API: unauthenticated=global only, NC=global+their networks - Send api_token with tag list requests for proper user-based filtering - Add network_name to Tag resource for UI grouping 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
NCs can now add global tags and tags from their networks, but not tags from other networks. Updated testApprove to verify this behavior: - NC CAN add global tags (network_id = null) - NC CANNOT add tags from networks they don't coordinate 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update listTagsv2() to only return network tags to NCs (not global) - Update updateGroupv2() to prevent NCs from adding global tags - Update getNetworkTagsv2() to only show global tags to admins - Update tests to reflect new global tags = admin-only rule 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix tag visibility intersection: NCs can only see/edit tags from networks where they coordinate AND the group belongs - NC tag updates preserve tags from other networks they don't coordinate - Add tag badges to group list view for NCs and admins - Groups list tag filter now visible to NCs (was admin-only) - Convert network page to Vue with stats and tag management - Add groups_count to Tag resource for deletion warnings - Add PHPUnit tests for tag intersection logic - Update .gitignore for Vite build artifacts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update translation strings to use Laravel pluralization syntax
- Enhanced JS choice() function to handle {n} and [n,*] syntax
- Fixed networks.general.count, show.groups_count, add_groups_success
- Fixed tags.delete_warning pluralization
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Reverts accidental port change that broke CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This reverts commit d60519e.
- Taskfile.yml: Update wait_for_service check to use port 8026 - CLAUDE.md: Update Mailhog URL - docs/local-development.md: Update Mailhog URL 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Refactored to recursively process nested translation structures instead of failing when encountering arrays. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Logs EventsUsers status and role to help diagnose why attending is sometimes true when it should be false in CI. Also adds test artifacts to .gitignore. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add fr and fr-BE translations for new network strings - Remove unused translation keys (general.count, show.about_modal_header) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use "Etiquette" (without accent) to match existing usage - Use "Repair Café" instead of "groupe" for consistency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Removed fwrite(STDERR) which was causing TeamCity to mark the test as failed even when assertions passed. Debug info now only appears in assertion failure messages. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- /api/v2/networks/{id}/tags returns empty for unauthenticated users
- /api/v2/groups/tags returns empty for unauthenticated users
- Added tests for both endpoints
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test occasionally fails in CI with all_confirmed_restarters_count being 1 instead of 0. Added debug info to show group membership state when assertion fails. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After making unauthenticated API calls return empty tags, the test needs to authenticate first to see the tags. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The test expected unauthenticated users to see network tags, but we changed the API to return empty for unauthenticated users. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Must be authenticated to see tags after unauthenticated API change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Center title and intro text on landing page - Reduce line-height on h1 for tighter title spacing - Add white-space: nowrap to stat headers to prevent line breaks - Add missing description field to skills seeder (required NOT NULL column) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use more specific selector (label.btn.btn-checkbox) for higher specificity - Override background color to gray (#E4E4E4) - Remove uppercase text-transform - Add background-image: none to prevent gradient overrides Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add docker:vite, docker:vite:start, docker:vite:stop tasks - Change HMR host from hardcoded www.example.com to env variable with localhost default - Update CLAUDE.md with critical Docker task command documentation Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create EmailValidation.vue component that checks if email already exists on blur and displays validation message. Replaces inline HTML with proper Vue component following codebase patterns. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The templates use kebab-case (<categories-table>, <roles-table>) but components were registered without hyphens. Vue's template-to-component resolution requires matching names. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Past events were missing timezone in the expanded event data, causing date/time display issues on group pages. Now explicitly passing timezone alongside event_date_local, start_local, and end_local. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The route was incorrectly placed in the ensureAPIToken middleware group but requires authentication since it calls auth()->user(). Moved to the auth+verifyUserConsent+ensureAPIToken group where it belongs. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Hide hosts section in EventDetails when no hosts assigned - Update StatsShare to use __() instead of $lang.get/choice methods Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Brings in post-release fixes: - Event invite modal converted to Vue component with Tab key support - Fix notifications mark as read (event delegation) - Fix skills list dropdown arrow and add Ctrl-click hint - Fix landing page 'Waste prevented' layout wrapping Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… collapsible sections, CI deploy option - Reorganised to lead with What Changes / What Stays the Same - Added Metabase direct DB access as known risk - Moved Fly config setup to pre-cutover (days before, not during maintenance window) - Added CircleCI automated deploy option - Clarified DNS is at iwantmyname.com (not Cloudflare, no CNAME flattening) - Made all sections collapsible with <details> tags - Fixed section numbering Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… title are on same line Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On Fly.io, nginx serves /uploads/ from Tigris (S3), not local disk. FixometerFile writes to local disk for Intervention Image processing, but those files were never synced to Tigris, so images were broken. After local processing (orientation fix, thumbnail/mid generation), files are now synced to S3 via Storage facade. The syncToCloud method is a no-op when FILESYSTEM_DISK is not 's3', so existing production and test environments are unaffected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…, hauts-de-france) All three point to current production server and need DNS + TLS certs on Fly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… DNS cutover Wildcard cert already created on Fly. Needs _acme-challenge CNAME at iwantmyname.com for DNS-01 validation (can be done before cutover). Covers repairtogether, repairshare, hauts-de-france subdomains. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Deploy L10+Fly first, group tags later as preview - Scale up to shared-cpu-2x/4GB for launch - Fix MAIL_FROM_ADDRESS to noreply@mg.restarters.net - Hourly backups to Google Drive, Metabase pulls from there - Simplified rollback: just switch DNS back - Add API compatibility check for third parties - Add ERES preview deployment plan - Concrete timeline: migration ~Apr 9, group tags ~Apr 30 - Note production branch cleanup needed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Mount /var/log as persistent volume so logs survive redeploys - Add request timing to nginx access log (rt, uct, uht, urt fields) - Enable PHP-FPM slow log (5s threshold) and request_terminate_timeout (60s) - Install sysstat and run sar collection every 60s via supervisord - Create log directories on volume in startup.sh Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Health check was hitting the homepage which runs Fixometer::loginRegisterStats() causing 60s+ timeouts and saturating PHP-FPM workers. /robots.txt is a static file served by nginx without touching PHP. Added logrotate for nginx and PHP-FPM slow logs (14 day retention). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Symlinks /var/www/storage/framework/cache/data to /var/log/cache/data on the persistent volume. Previously the cache was on ephemeral container storage and blown away on every deploy, causing 15s+ homepage loads while Fixometer stats recalculated. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Homepage request causes PHP-FPM to spike to ~400MB, exhausting all available memory (985MB total, ~400MB free at idle). Without swap, the OOM killer terminates PHP-FPM workers causing 502 errors. Uses fallocate (instant) with dd fallback. On root fs, recreated each boot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The all_stats cache was storing 17,291 full Party model objects (96MB serialized). Every homepage load deserialized this, taking 5+ seconds. Only the count was ever used. Now caches just the integer count. Cache file drops from 96MB to 112KB, read time from 5s to <1ms. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Includes: persistent logging, swap, health check fix, cache optimisation, FixometerFile S3 sync. Resolved conflicts keeping group_tags' COUNT query approach for party stats. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| if [[ -n "$DB_PASS" ]]; then | ||
| log_step "Setting MYSQL_PASSWORD and MYSQL_ROOT_PASSWORD on ${FLY_DB_APP}..." | ||
| if [[ "$DRY_RUN" = true ]]; then | ||
| log_dry "echo 'MYSQL_PASSWORD=***\nMYSQL_ROOT_PASSWORD=***' | fly secrets import -a ${FLY_DB_APP}" |
Check failure
Code scanning / SonarCloud
MySQL database passwords should not be disclosed High
| if [[ "$DRY_RUN" = true ]]; then | ||
| log_dry "echo 'MYSQL_PASSWORD=***\nMYSQL_ROOT_PASSWORD=***' | fly secrets import -a ${FLY_DB_APP}" | ||
| else | ||
| printf "MYSQL_PASSWORD=%s\nMYSQL_ROOT_PASSWORD=%s\n" "$DB_PASS" "$DB_PASS" \ |
Check failure
Code scanning / SonarCloud
MySQL database passwords should not be disclosed High
Bug 1: Edit tag modal now prevents auto-close on OK, shows duplicate
name error inline instead of silently closing.
Bug 2: "Group could not be edited" when adding/removing tags - fixed
archived_at validation to be nullable (empty string was failing date
validation) and FormData filter to not drop falsy values.
Bug 3: /api/v2/networks/{id}/tags returns empty without api_token -
this is expected API behaviour, not a bug. The UI passes the token.
Feature 1: Tags now displayed as badges on individual group page
in GroupHeading component, below the group name.
Feature 2: API already uses 'group_tag' parameter name (not 'tag').
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The public/hot file (created by local Vite dev server) was being copied into the Docker image, causing Laravel to load assets from localhost:5173 instead of the built files. Added to .dockerignore and rm -f after build. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- NetworkController: simplify getNetworkTagsv2 to return only network-specific tags (public endpoint), fixing empty response for unauthenticated requests - NetworkController: accept both 'tag' and 'group_tag' params for stats filter - GroupAddEdit.vue: remove admin bypass in tag filtering so admins only see tags from networks the group belongs to (not all networks) - LoginController: add try-catch logging around post-auth to capture 500 errors - Update test to match new public tags endpoint behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The mediawiki-api v3.1 changed its namespace from Mediawiki\Api\MediawikiApi to Addwiki\Mediawiki\Api\Client\MediaWiki. The old catch(\Exception) didn't catch the resulting Error (class not found), causing a 500 on every login when the login event listener tried to resolve the MediaWiki service. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The addwiki/mediawiki-api v3.1 changed namespace from Mediawiki\Api to Addwiki\Mediawiki\Api. This causes Error (not Exception) when class not found. Changed catch(\Exception) to catch(\Throwable) in all mediawiki integration points so login doesn't 500. Made UserCreator constructor param nullable since it may fail to resolve. Wiki integration itself needs a separate v3 namespace migration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New public endpoint GET /api/v2/networks/{id}/stats?group_tag={tagId}
returns network impact statistics, optionally filtered by group tag.
Includes OpenAPI annotations and two feature tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Configure phpMyAdmin as publicly accessible Fly app with basic auth - Add docker/Dockerfile.pma for custom phpMyAdmin image - Upgrade @playwright/test to 1.59.1 - Add .mcp.json to .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… Admin, API) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers all test cases from Neil's testing doc: - NC: group page tag display, all network tag CRUD, group tag management - Admin: network tag CRUD, group tag management, group page display - Admin: global tag management (/tags page) - view, create, edit, delete - Host: verified no tag visibility on groups list and group page - API: tags, groups/events/stats filtered by tag Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add NC user, host user, network, and group creation to Taskfile Playwright setup so grouptags tests have required data in CI - Make "tags displayed on group page" tests self-contained by creating and assigning a tag before checking the view page, rather than relying on state from earlier tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use .first() on table locators that can match multiple elements in CI environment where page may contain multiple tables. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bring in the Laravel 10 upgrade (via PR #816 merge) plus develop drift. Single conflict in app/Listeners/LogInToWiki.php constructor signature: kept develop's ?UserCreator $mediawikiUserCreator (nullable type, no default) over the older UserCreator $mediawikiUserCreator = null form. Both work with the MediawikiServiceProvider binding that returns null when Wiki is unavailable; keeping develop's form for consistency with the tested wiki-fallback flow. package-lock.json regenerated via npm install.
|
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Summary
/api/v2/networks/{id}/tagsAlso includes merge of Laravel 10 upgrade branch.
Related
Test plan
🤖 Generated with Claude Code