Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ BinktermPHP is a multi-protocol BBS platform built around native FTN messaging.
- For version bump steps and UPGRADING doc format, invoke the `/bump-version` skill.
- **UPGRADING doc content rules**: Do not include sentences stating that no configuration is needed, no sysop action is required, or no migration is required. These are filler — omit them entirely.
- When creating or modifying a WebDoor, invoke the `/new-webdoor` skill.
- Write phpDoc blocks when possible
- **phpDoc requirement**: New PHP classes must include a class-level phpDoc block. New public methods should include phpDoc by default unless the signature and behavior are both trivial and self-explanatory.

## PostgreSQL Gotchas

Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"twig/twig": "^3.7",
"ext-pdo": "*",
"ext-pgsql": "*",
"ext-ftp": "*",
"phpmailer/phpmailer": "^6.8",
"chillerlan/php-qrcode": "^4.3"
},
Expand Down
79 changes: 79 additions & 0 deletions config/i18n/de/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,9 @@
'ui.admin_users.admin_privileges_help' => 'Administratoren können Benutzer und Systemeinstellungen verwalten',
'ui.admin_users.is_system_account' => 'Ist ein Systemkonto',
'ui.admin_users.is_system_account_help' => 'Systemkonten werden in der normalen Benutzerliste ausgeblendet und sind für interne Zwecke oder Dienste reserviert.',
'ui.admin_users.is_bbs_account' => 'Ist ein BBS-Konto',
'ui.admin_users.is_bbs_account_help' => 'BBS-Konten können QWK-Antworten mit dem From-Namen aus dem entfernten Paket importieren statt mit dem Namen des lokalen Kontos.',
'ui.admin_users.is_bbs_account_badge' => 'BBS',
'ui.admin_users.email_optional_help' => 'Optional - for account recovery and notifications',
'ui.admin_users.min_8_characters' => 'Minimum 8 characters',
'ui.admin_users.username_cannot_change' => 'Benutzername cannot be changed',
Expand Down Expand Up @@ -2453,6 +2456,10 @@
'ui.echoareas.legend_administrative' => 'Administrative',
'ui.echoareas.legend_special_interest' => 'Special interest',
'ui.echoareas.legend_regional' => 'Regional',
'ui.echoareas.editor_section_identity' => 'Identitat',
'ui.echoareas.editor_section_appearance' => 'Darstellung und Posting',
'ui.echoareas.editor_section_policy' => 'Zugang und Richtlinien',
'ui.echoareas.editor_section_transport' => 'Transport und Weiterleitung',
'ui.echoareas.tag_required' => 'Tag *',
'ui.echoareas.tag_help' => 'Echo-Bereich tag (e.g., FIDONET.GEN, LOCAL.TEST)',
'ui.echoareas.description_required' => 'Beschreibung *',
Expand Down Expand Up @@ -2495,6 +2502,14 @@
'ui.echoareas.allow_media_deny' => 'Deaktiviert',
'ui.echoareas.delete_confirm_prefix' => 'Möchtest Du diesen Echo-Bereich wirklich löschen',
'ui.echoareas.delete_confirm_warning' => 'Diese Aktion kann nicht rückgängig gemacht werden und wirkt sich auf das Nachrichten-Routing aus.',
'ui.echoareas.delete_message_handling' => 'Was soll mit den verbleibenden Nachrichten geschehen?',
'ui.echoareas.select_delete_action' => 'Aktion auswählen',
'ui.echoareas.delete_messages_action' => 'Sie löschen',
'ui.echoareas.move_messages_action' => 'In einen anderen Bereich verschieben',
'ui.echoareas.delete_move_note' => 'Das Verschieben weist Nachrichten nur lokal neu zu. Alte Nachrichten werden nicht erneut weitergeleitet oder veröffentlicht.',
'ui.echoareas.move_messages_target' => 'Nachrichten verschieben nach',
'ui.echoareas.select_target_area' => 'Zielbereich auswählen',
'ui.echoareas.delete_targets_failed' => 'Zielbereiche konnten nicht geladen werden',
'ui.echoareas.none_found' => 'Keine Echo-Bereiche gefunden',
'ui.echoareas.tag' => 'Tag',
'ui.echoareas.messages' => 'Nachrichten',
Expand Down Expand Up @@ -4940,6 +4955,8 @@
'ui.admin.networks.add_network' => 'Add Network',
'ui.admin.networks.edit_network' => 'Edit Network',
'ui.admin.networks.type' => 'Type',
'ui.admin.networks.type_fidonet' => 'FidoNet',
'ui.admin.networks.type_qwk' => 'QWK',
'ui.admin.networks.domain' => 'Domain',
'ui.admin.networks.name' => 'Name',
'ui.admin.networks.description' => 'Description',
Expand All @@ -4959,4 +4976,66 @@
'ui.admin.networks.deleted' => 'Network deleted',
'ui.admin.networks.change_domain_failed' => 'Failed to change domain',
'ui.admin.networks.domain_changed' => 'Domain changed',
'ui.admin.networks.search_placeholder' => 'Search domain, name, description, website, or uplink...',
'ui.admin.networks.none' => 'No networks found',
'ui.qwk.uplinks.manage' => 'QWK Mailboxes',
'ui.qwk.uplinks.list_title' => 'Configured Mailboxes',
'ui.qwk.uplinks.add_title' => 'Add QWK Mailbox',
'ui.qwk.uplinks.edit_title' => 'Edit QWK Mailbox',
'ui.qwk.uplinks.bbs_id' => 'Remote BBS ID',
'ui.qwk.uplinks.remote_path' => 'Remote FTP Path',
'ui.qwk.uplinks.passive_mode' => 'Passive Mode',
'ui.qwk.uplinks.poll_schedule' => 'Poll Schedule',
'ui.qwk.uplinks.load_failed' => 'Failed to load QWK mailboxes',
'ui.qwk.uplinks.save_failed' => 'Failed to save QWK mailbox',
'ui.qwk.uplinks.delete_failed' => 'Failed to delete QWK mailbox',
'ui.qwk.uplinks.poll_failed' => 'Failed to poll QWK mailbox',
'ui.qwk.uplinks.none' => 'No QWK mailboxes configured',
'ui.qwk.uplinks.last_polled' => 'Last polled',
'ui.qwk.uplinks.poll_now' => 'Poll now',
'ui.qwk.uplinks.saved' => 'QWK mailbox saved',
'ui.qwk.uplinks.deleted' => 'QWK mailbox deleted',
'ui.qwk.uplinks.delete_confirm' => 'Delete this QWK mailbox?',
'ui.qwk.uplinks.polled' => 'QWK mailbox polled',
'ui.qwk.uplinks.polling' => 'Polling QWK mailbox...',
'ui.qwk.uplinks.result_download' => 'Downloaded packet',
'ui.qwk.uplinks.result_imported' => 'Imported',
'ui.qwk.uplinks.result_skipped' => 'Skipped',
'ui.qwk.uplinks.result_rep_created' => 'Built REP packet',
'ui.qwk.uplinks.result_uploaded' => 'Uploaded REP',
'ui.qwk.uplinks.result_dry_run' => 'Skipped (dry run)',
'ui.qwk.echoarea.subscriptions_title' => 'Transportverbindungen',
'ui.qwk.echoarea.subscriptions_help' => 'Verbinden Sie diesen Echo-Bereich mit externen Transport-Endpunkten wie QWK-Mailboxen.',
'ui.qwk.echoarea.relay_title' => 'Importweiterleitung',
'ui.qwk.echoarea.relay_help' => 'Steuert, ob über Transport importierte Nachrichten an andere verbundene Transporte dieses Bereichs weitergeleitet werden.',
'ui.qwk.echoarea.relay_mode_none' => 'Keine Weiterleitung',
'ui.qwk.echoarea.relay_mode_none_short' => 'Aus',
'ui.qwk.echoarea.relay_mode_auto' => 'Automatisch an alle anderen verbundenen Transporte weiterleiten',
'ui.qwk.echoarea.relay_mode_auto_short' => 'Auto',
'ui.qwk.echoarea.relay_mode_manual' => 'Manuelle Weiterleitungsregeln',
'ui.qwk.echoarea.relay_rules_title' => 'Manuelle Weiterleitungsregeln',
'ui.qwk.echoarea.relay_rules_help' => 'Wählen Sie, welche transport-importierten Nachrichten an andere verbundene Transporte weitergeleitet werden dürfen.',
'ui.qwk.echoarea.relay_rules_unavailable' => 'Verbinden Sie mehr als einen Transport, um manuelle Weiterleitungsregeln zu nutzen.',
'ui.qwk.echoarea.none_subscriptions' => 'Noch keine Transportverbindungen',
'ui.qwk.echoarea.none_gates' => 'Keine Gates konfiguriert',
'ui.qwk.echoarea.local_only_notice' => 'Externe Transport-Weiterleitung ist deaktiviert, solange dieser Bereich als Local Only markiert ist.',
'ui.qwk.echoarea.summary_subscriptions' => '{count} verknupft',
'ui.qwk.echoarea.summary_subscriptions_none' => 'Keine',
'ui.qwk.echoarea.summary_gates' => '{count} konfiguriert',
'ui.qwk.echoarea.summary_gates_none' => 'Keine',
'ui.qwk.echoarea.summary_rules' => '{count} Regeln',
'ui.qwk.echoarea.summary_rules_none' => 'Manuell',
'ui.qwk.echoarea.transport_ftn' => 'FTN',
'ui.qwk.echoarea.transport_qwk' => 'QWK',
'ui.qwk.echoarea.gates_title' => 'Gates',
'ui.qwk.echoarea.gates_help' => 'Mirror this area into other local echo areas.',
'ui.qwk.echoarea.none_configured' => 'None configured',
'ui.qwk.echoarea.uplink_label' => 'Verbindung',
'ui.qwk.echoarea.select_uplink' => 'Verbindung auswahlen',
'ui.qwk.echoarea.conference_tag' => 'Remote-Tag',
'ui.qwk.echoarea.conference_number' => 'Remote-ID',
'ui.qwk.echoarea.gate_target' => 'Target Area',
'ui.qwk.echoarea.select_gate_target' => 'Select target area',
'ui.qwk.echoarea.bidirectional' => 'Bidirectional',
'ui.qwk.echoarea_config_saved' => 'QWK subscriptions and gates saved',
];
7 changes: 7 additions & 0 deletions config/i18n/de/errors.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@
'errors.echoareas.not_found_or_unchanged' => 'Echo-Bereich nicht gefunden or no changes made',
'errors.echoareas.update_failed' => 'Echo-Bereich konnte nicht aktualisiert werden',
'errors.echoareas.delete_blocked_has_messages' => 'Cannot delete echo area with existing messages',
'errors.echoareas.delete_action_required' => 'Wähle vor dem Löschen dieses Echo-Bereichs aus, was mit den verbleibenden Nachrichten geschehen soll',
'errors.echoareas.delete_invalid_action' => 'Ungültige Löschaktion ausgewählt',
'errors.echoareas.delete_move_target_required' => 'Wähle einen Ziel-Echo-Bereich zum Verschieben der verbleibenden Nachrichten aus',
'errors.echoareas.delete_move_target_invalid' => 'Der ausgewählte Ziel-Echo-Bereich ist ungültig',
'errors.echoareas.delete_failed' => 'Echo-Bereich konnte nicht gelöscht werden',

// File Areas
Expand Down Expand Up @@ -722,4 +726,7 @@
'errors.meshcore.not_found' => 'Kontakt nicht gefunden.',
'errors.meshcore.qr_unrecognized' => 'Unbekanntes QR-Code-Format.',
'errors.meshcore.qr_camera_denied' => 'Kamerazugriff verweigert.',
'errors.qwk.uplink_not_found' => 'QWK mailbox not found',
'errors.qwk.invalid_uplink' => 'Invalid QWK mailbox configuration',
'errors.qwk.poll_failed' => 'Failed to poll QWK mailbox',
];
79 changes: 79 additions & 0 deletions config/i18n/en/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,9 @@
'ui.admin_users.admin_privileges_help' => 'Admins can manage users and system settings',
'ui.admin_users.is_system_account' => 'Is System Account',
'ui.admin_users.is_system_account_help' => 'System accounts are hidden from the normal user list and reserved for internal or service use.',
'ui.admin_users.is_bbs_account' => 'Is BBS Account',
'ui.admin_users.is_bbs_account_help' => 'BBS accounts may import QWK replies using the remote packet\'s From name instead of the local account name.',
'ui.admin_users.is_bbs_account_badge' => 'BBS',
'ui.admin_users.email_optional_help' => 'Optional - for account recovery and notifications',
'ui.admin_users.min_8_characters' => 'Minimum 8 characters',
'ui.admin_users.username_cannot_change' => 'Username cannot be changed',
Expand Down Expand Up @@ -2471,6 +2474,10 @@
'ui.echoareas.legend_administrative' => 'Administrative',
'ui.echoareas.legend_special_interest' => 'Special interest',
'ui.echoareas.legend_regional' => 'Regional',
'ui.echoareas.editor_section_identity' => 'Identity',
'ui.echoareas.editor_section_appearance' => 'Appearance and posting',
'ui.echoareas.editor_section_policy' => 'Access and policy',
'ui.echoareas.editor_section_transport' => 'Transport and relay',
'ui.echoareas.tag_required' => 'Tag *',
'ui.echoareas.tag_help' => 'Echo area tag (e.g., FIDONET.GEN, LOCAL.TEST)',
'ui.echoareas.description_required' => 'Description *',
Expand Down Expand Up @@ -2513,6 +2520,14 @@
'ui.echoareas.allow_media_deny' => 'Disabled',
'ui.echoareas.delete_confirm_prefix' => 'Are you sure you want to delete the echo area',
'ui.echoareas.delete_confirm_warning' => 'This action cannot be undone and will affect message routing.',
'ui.echoareas.delete_message_handling' => 'What should happen to the remaining messages?',
'ui.echoareas.select_delete_action' => 'Select an action',
'ui.echoareas.delete_messages_action' => 'Delete them',
'ui.echoareas.move_messages_action' => 'Move them to another area',
'ui.echoareas.delete_move_note' => 'Moving messages only reassigns them locally. It does not re-gate or republish old messages.',
'ui.echoareas.move_messages_target' => 'Move messages to',
'ui.echoareas.select_target_area' => 'Select target area',
'ui.echoareas.delete_targets_failed' => 'Failed to load target echo areas',
'ui.echoareas.none_found' => 'No echo areas found',
'ui.echoareas.tag' => 'Tag',
'ui.echoareas.messages' => 'Messages',
Expand Down Expand Up @@ -4962,6 +4977,8 @@
'ui.admin.networks.add_network' => 'Add Network',
'ui.admin.networks.edit_network' => 'Edit Network',
'ui.admin.networks.type' => 'Type',
'ui.admin.networks.type_fidonet' => 'FidoNet',
'ui.admin.networks.type_qwk' => 'QWK',
'ui.admin.networks.domain' => 'Domain',
'ui.admin.networks.name' => 'Name',
'ui.admin.networks.description' => 'Description',
Expand All @@ -4981,4 +4998,66 @@
'ui.admin.networks.deleted' => 'Network deleted',
'ui.admin.networks.change_domain_failed' => 'Failed to change domain',
'ui.admin.networks.domain_changed' => 'Domain changed',
'ui.admin.networks.search_placeholder' => 'Search domain, name, description, website, or uplink...',
'ui.admin.networks.none' => 'No networks found',
'ui.qwk.uplinks.manage' => 'QWK Mailboxes',
'ui.qwk.uplinks.list_title' => 'Configured Mailboxes',
'ui.qwk.uplinks.add_title' => 'Add QWK Mailbox',
'ui.qwk.uplinks.edit_title' => 'Edit QWK Mailbox',
'ui.qwk.uplinks.bbs_id' => 'Remote BBS ID',
'ui.qwk.uplinks.remote_path' => 'Remote FTP Path',
'ui.qwk.uplinks.passive_mode' => 'Passive Mode',
'ui.qwk.uplinks.poll_schedule' => 'Poll Schedule',
'ui.qwk.uplinks.load_failed' => 'Failed to load QWK mailboxes',
'ui.qwk.uplinks.save_failed' => 'Failed to save QWK mailbox',
'ui.qwk.uplinks.delete_failed' => 'Failed to delete QWK mailbox',
'ui.qwk.uplinks.poll_failed' => 'Failed to poll QWK mailbox',
'ui.qwk.uplinks.none' => 'No QWK mailboxes configured',
'ui.qwk.uplinks.last_polled' => 'Last polled',
'ui.qwk.uplinks.poll_now' => 'Poll now',
'ui.qwk.uplinks.saved' => 'QWK mailbox saved',
'ui.qwk.uplinks.deleted' => 'QWK mailbox deleted',
'ui.qwk.uplinks.delete_confirm' => 'Delete this QWK mailbox?',
'ui.qwk.uplinks.polled' => 'QWK mailbox polled',
'ui.qwk.uplinks.polling' => 'Polling QWK mailbox...',
'ui.qwk.uplinks.result_download' => 'Downloaded packet',
'ui.qwk.uplinks.result_imported' => 'Imported',
'ui.qwk.uplinks.result_skipped' => 'Skipped',
'ui.qwk.uplinks.result_rep_created' => 'Built REP packet',
'ui.qwk.uplinks.result_uploaded' => 'Uploaded REP',
'ui.qwk.uplinks.result_dry_run' => 'Skipped (dry run)',
'ui.qwk.echoarea.subscriptions_title' => 'Transport Connections',
'ui.qwk.echoarea.subscriptions_help' => 'Connect this echo area to external transport endpoints such as QWK mailboxes.',
'ui.qwk.echoarea.relay_title' => 'Imported Message Relay',
'ui.qwk.echoarea.relay_help' => 'Controls whether transport-imported messages are relayed to other connected transports for this area.',
'ui.qwk.echoarea.relay_mode_none' => 'No relay',
'ui.qwk.echoarea.relay_mode_none_short' => 'Off',
'ui.qwk.echoarea.relay_mode_auto' => 'Auto relay to all other connected transports',
'ui.qwk.echoarea.relay_mode_auto_short' => 'Auto',
'ui.qwk.echoarea.relay_mode_manual' => 'Manual relay rules',
'ui.qwk.echoarea.relay_rules_title' => 'Manual Relay Rules',
'ui.qwk.echoarea.relay_rules_help' => 'Choose which transport-imported messages may relay to other connected transports.',
'ui.qwk.echoarea.relay_rules_unavailable' => 'Connect more than one transport to use manual relay rules.',
'ui.qwk.echoarea.none_subscriptions' => 'No transport connections yet',
'ui.qwk.echoarea.none_gates' => 'No gates configured',
'ui.qwk.echoarea.local_only_notice' => 'External transport relay is disabled while this area is marked Local Only.',
'ui.qwk.echoarea.summary_subscriptions' => '{count} linked',
'ui.qwk.echoarea.summary_subscriptions_none' => 'None',
'ui.qwk.echoarea.summary_gates' => '{count} configured',
'ui.qwk.echoarea.summary_gates_none' => 'None',
'ui.qwk.echoarea.summary_rules' => '{count} rules',
'ui.qwk.echoarea.summary_rules_none' => 'Manual',
'ui.qwk.echoarea.transport_ftn' => 'FTN',
'ui.qwk.echoarea.transport_qwk' => 'QWK',
'ui.qwk.echoarea.gates_title' => 'Gates',
'ui.qwk.echoarea.gates_help' => 'Mirror this area into other local echo areas.',
'ui.qwk.echoarea.none_configured' => 'None configured',
'ui.qwk.echoarea.uplink_label' => 'Connection',
'ui.qwk.echoarea.select_uplink' => 'Select connection',
'ui.qwk.echoarea.conference_tag' => 'Remote Tag',
'ui.qwk.echoarea.conference_number' => 'Remote ID',
'ui.qwk.echoarea.gate_target' => 'Target Area',
'ui.qwk.echoarea.select_gate_target' => 'Select target area',
'ui.qwk.echoarea.bidirectional' => 'Bidirectional',
'ui.qwk.echoarea_config_saved' => 'QWK subscriptions and gates saved',
];
7 changes: 7 additions & 0 deletions config/i18n/en/errors.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@
'errors.echoareas.not_found_or_unchanged' => 'Echo area not found or no changes made',
'errors.echoareas.update_failed' => 'Failed to update echo area',
'errors.echoareas.delete_blocked_has_messages' => 'Cannot delete echo area with existing messages',
'errors.echoareas.delete_action_required' => 'Choose what to do with the remaining messages before deleting this echo area',
'errors.echoareas.delete_invalid_action' => 'Invalid delete action selected',
'errors.echoareas.delete_move_target_required' => 'Select a target echo area to move the remaining messages',
'errors.echoareas.delete_move_target_invalid' => 'Selected target echo area is invalid',
'errors.echoareas.delete_failed' => 'Failed to delete echo area',

// File Areas
Expand Down Expand Up @@ -722,4 +726,7 @@
'errors.meshcore.not_found' => 'Contact not found.',
'errors.meshcore.qr_unrecognized' => 'Unrecognized QR code format.',
'errors.meshcore.qr_camera_denied' => 'Camera access denied.',
'errors.qwk.uplink_not_found' => 'QWK mailbox not found',
'errors.qwk.invalid_uplink' => 'Invalid QWK mailbox configuration',
'errors.qwk.poll_failed' => 'Failed to poll QWK mailbox',
];
Loading
Loading