Sync Testing Guide - Local Development
Date: 2025-12-29 Changes Made: Added configurable ForeningLet write protection
What Changed
Files Modified:
- config/fanafdelingen.php
-
Added
foreninglet_writes_enabledflag -
.env.example
-
Added
FORENINGLET_WRITES_ENABLEDdocumentation -
app/Actions/Fanafdelingen/CreateMemberInForeningLet.php
-
Updated environment check to respect config flag
-
app/Actions/Fanafdelingen/CancelMembershipInForeningLet.php
-
Updated environment check to respect config flag
-
app/Actions/Fanafdelingen/ConvertToCombiMember.php
-
Updated environment check to respect config flag
-
app/Actions/Fanafdelingen/ConvertToRegularMember.php
- Updated environment check to respect config flag
How It Works
Logic:
if (!App::environment('production') && !config('fanafdelingen.flags.foreninglet_writes_enabled', false)) {
return; // Block the write
}
Behavior by Environment:
| Environment | Flag Value | Result |
|---|---|---|
| Production | Any | ✅ Writes ALWAYS allowed |
| Local | false (default) |
🚫 Writes blocked (SAFE) |
| Local | true |
✅ Writes allowed (USE WITH CAUTION) |
| Staging | false (default) |
🚫 Writes blocked (SAFE) |
| Staging | true |
✅ Writes allowed |
Safe Operations (Always Work)
These operations only READ from ForeningLet - safe in any environment:
✅ Sync Members from ForeningLet
php artisan tinker
\App\Actions\Fanafdelingen\SyncMembersFromForeningLet::dispatch();
✅ Sync Activities from ForeningLet
php artisan tinker
\App\Actions\Fanafdelingen\SyncActivitiesFromForeningLet::dispatch();
✅ Sync from Brøndby Support
php artisan tinker
\App\Actions\BrondbySupport\SyncMembersFromBrondbySupport::dispatch();
✅ Full Sync (Orchestrated)
php artisan tinker
\App\Actions\SyncAllSystemsInBatch::dispatch();
These are SAFE - they: - Read from external APIs - Write to your LOCAL database only - Never modify ForeningLet data
Blocked Operations (Protected)
These operations WRITE to ForeningLet - blocked by default in local:
🚫 Create Member (blocked in local by default)
# This will be blocked in local unless flag is enabled
\App\Actions\Fanafdelingen\CreateMemberInForeningLet::dispatch([...]);
🚫 Cancel Membership (blocked in local by default)
# This will be blocked in local unless flag is enabled
\App\Actions\Fanafdelingen\CancelMembershipInForeningLet::dispatch($memberId);
🚫 Convert to Combi (blocked in local by default)
# This will be blocked in local unless flag is enabled
\App\Actions\Fanafdelingen\ConvertToCombiMember::dispatch($member);
🚫 Convert to Regular (blocked in local by default)
# This will be blocked in local unless flag is enabled
\App\Actions\Fanafdelingen\ConvertToRegularMember::dispatch($member);
Testing in Local Environment
Default Behavior (Safe - Read Only)
Your .env file (or no flag set):
# FORENINGLET_WRITES_ENABLED not set (defaults to false)
What you can do: - ✅ Sync members from ForeningLet - ✅ Sync activities from ForeningLet - ✅ Sync from Brøndby Support - ✅ View all data in Filament admin - ✅ Test linking logic (updates local DB only) - ✅ Test bulk actions (they'll silently skip writes) - 🚫 Cannot create members in ForeningLet - 🚫 Cannot update members in ForeningLet - 🚫 Cannot cancel memberships in ForeningLet
Enable Writes (Advanced - Use with Caution)
If you need to test the full flow including writes:
- Update your
.envfile:
FORENINGLET_WRITES_ENABLED=true
- Clear config cache:
php artisan config:clear
- Now writes will work:
php artisan tinker
\App\Actions\Fanafdelingen\CreateMemberInForeningLet::dispatch([
'first_name' => 'Test',
'last_name' => 'User',
'email' => 'test@example.com',
// ... other fields
]);
⚠️ WARNING: This will actually create/modify data in ForeningLet!
- When done, disable again:
# In .env
FORENINGLET_WRITES_ENABLED=false
php artisan config:clear
Recommended Testing Workflow
Step 1: Verify Local is Safe (First Time Setup)
# Check your .env file
cat .env | grep FORENINGLET_WRITES_ENABLED
# If it's not there or set to false, you're safe
# If it's set to true, change it to false!
# Clear any cached config
php artisan config:clear
Step 2: Run Safe Sync Operations
php artisan tinker
# Sync activities (safe - read only)
>>> \App\Actions\Fanafdelingen\SyncActivitiesFromForeningLet::run();
# Sync members (safe - read only)
>>> \App\Actions\Fanafdelingen\SyncMembersFromForeningLet::run();
# Sync BS members (safe - read only)
>>> \App\Actions\BrondbySupport\SyncMembersFromBrondbySupport::run();
# Check how many members were synced
>>> \App\Models\Member::count();
>>> \App\Models\BrondbySupportMember::count();
>>> \App\Models\Activity::count();
Step 3: Test in Filament Admin
# Start the dev server
php artisan serve
# Or if using Herd
composer run dev
Open: http://localhost:8000/admin (or your Herd URL)
What you can test safely: - Browse members - Browse BS members - Check linking status - View sync logs - Click bulk actions (they'll be blocked, but UI works)
What will be blocked: - "Opret medlemskab af FA" bulk action - "Opsig medlemskab i FA" bulk action - "Konvertér til kombimedlemmer" bulk action - These will execute but silently skip the ForeningLet API calls
Step 4: Test Linking Logic (Safe)
The linking logic only updates your LOCAL database:
php artisan tinker
# Get an unconnected BS member
>>> $bsMember = \App\Models\BrondbySupportMember::unconnectedMembers()->first();
# Test the linking action (only updates local DB)
>>> \App\Actions\BrondbySupport\ConnectBrondbySupportMemberWithFanafdelingenMember::run($bsMember);
# Check if it worked
>>> $bsMember->refresh();
>>> $bsMember->membershipById; // Should show linked member
This is SAFE because it only sets the bs_member_id column in your local database.
Production Deployment
Ensure Flag is Set Correctly
In production .env:
# You can either:
# 1. Not set it (production always allows writes anyway)
# 2. Set it to true (explicit, but redundant)
FORENINGLET_WRITES_ENABLED=true
# Or just leave it out entirely - production ignores the flag
The check in production:
if (!App::environment('production') && !config('...')) {
// This condition is FALSE in production
// Because !App::environment('production') = false
// So writes always work in production
}
After Deployment
Clear config cache:
php artisan config:cache
Test one write operation to verify:
php artisan tinker
# This should work in production
>>> \App\Actions\Fanafdelingen\ConvertToCombiMember::dispatch($someMember);
Troubleshooting
"Nothing happens when I run sync in local"
Check: 1. Are you getting any errors? 2. Check your database - are members being created? 3. Look at sync logs:
php artisan tinker
>>> \App\Models\SyncLog::latest()->get();
"I want to test a write action but it's blocked"
Option 1: Don't test the actual write The write actions are simple - they just send HTTP requests to ForeningLet API. The logic you want to test is probably the linking/sync logic, which is safe.
Option 2: Enable writes temporarily
# In .env
FORENINGLET_WRITES_ENABLED=true
# Clear cache
php artisan config:clear
# Test your action
# REMEMBER TO DISABLE AFTER
FORENINGLET_WRITES_ENABLED=false
php artisan config:clear
"How do I know if writes are blocked?"
Currently, the actions fail silently. You can add logging:
# Check sync logs for any failures
php artisan tinker
>>> \App\Models\SyncLog::where('status', 'error')->latest()->get();
Or add temporary logging to the action:
if (!App::environment('production') && !config('fanafdelingen.flags.foreninglet_writes_enabled', false)) {
\Log::info('ForeningLet write blocked', ['action' => 'CreateMember']);
return;
}
Then check: tail -f storage/logs/laravel.log
Quick Reference
Environment Check Commands
# What environment am I in?
php artisan tinker
>>> app()->environment();
# Is the flag enabled?
>>> config('fanafdelingen.flags.foreninglet_writes_enabled');
# Will writes be blocked?
>>> !app()->environment('production') && !config('fanafdelingen.flags.foreninglet_writes_enabled');
// true = writes blocked
// false = writes allowed
Safe Commands (Run Anytime)
# Sync everything (read only)
php artisan tinker
>>> \App\Actions\SyncAllSystemsInBatch::dispatch();
# Check what was synced
>>> \App\Models\Member::count();
>>> \App\Models\BrondbySupportMember::count();
>>> \App\Models\Activity::count();
# View recent sync logs
>>> \App\Models\SyncLog::latest()->take(10)->get();
Verify Protection is Working
php artisan tinker
# This should be blocked in local (unless flag enabled)
>>> \App\Actions\Fanafdelingen\CreateMemberInForeningLet::dispatch([
'first_name' => 'Test',
'last_name' => 'User',
'email' => 'willnotbecreated@test.com',
'is_member' => 0,
'enrollment' => now()->toDateString(),
'field2' => 99999,
'activity_ids' => [60123],
'receive_newsletter' => 1,
'note' => 'Test creation',
], null);
# Check ForeningLet - this user should NOT exist (unless you enabled writes)
Summary
✅ Your local environment is SAFE by default - Syncs work (read-only) - Writes are blocked - You can test everything except actual ForeningLet modifications
✅ Production is always enabled - Flag is ignored in production - All operations work normally
✅ You can enable writes if needed
- Set FORENINGLET_WRITES_ENABLED=true in .env
- Clear config cache
- Use with caution!
✅ Best practice - Keep flag disabled in local - Test with read operations only - Test write logic without actual API calls - Only enable for specific testing scenarios