Built-in Board Operator Guide
This guide covers the operational procedures for the built-in board (Notices / FAQ / 1:1 Inquiry). Be sure to review Getting Started first for the concepts and access paths.
Creating/deleting board containers is only possible for L1 SaaS and L2 Tenant operators. L3 organization operators can only manage posts and respond to inquiries for the boards in their own subtree. Sub-admins must be granted the boards / inquiries feature permissions for the menus to be visible.
1. Managing Board Containersβ
You manage board containers under Site Management β Boards (BoardResource, slug site-boards) in the SaaS, Tenant, and Org panels.
Creating a New Board (L1/L2)β
The board form consists of two sections.
Basic Information section
| Field | Description | Notes |
|---|---|---|
kind | Type (Notice/FAQ/Inquiry/General) | Cannot be changed for is_system boards |
name | Board display name | Max 150 characters, required |
key | Internal identifier key | Max 64 characters, cannot be changed for is_system boards |
audience_scope | Visibility scope (SaaS/Tenant/Org) | Default tenant |
audience_org_id | Target organization | Shown only when audience_scope = org |
site_key | Standalone site key | Leave empty for shared (null); specify to expose only on a specific standalone site |
Visibility/Placement section
| Field | Description | Default |
|---|---|---|
placement.app_nav | Toggle for menu visibility in the member App panel | true |
placement.sort | Sort order within App navigation | 0 |
is_active | Board activation | true |
sort | Sort order in the management list | 0 |
- Within a single tenant, the
(site_key, key)combination is unique (partial unique index; a NULLsite_keyis normalized to''). - If
audience_scopeisorg, the board is exposed to the specified organization and its entire subtree below it (regardless of depth).
List and Actionsβ
The board list shows the kind (badge), name, audience_scope, post count (posts_count), is_active, and is_system columns. The default sort is ascending by sort.
- Edit: Performed per row via
EditActionby any operator (based on view permission). - Bulk delete:
DeleteBulkActionis shown only to those withlevel <= 2(L1/L2).
is_system Protectionβ
The default boards seeded by CoreSeeder (Notice/FAQ/Inquiry) are protected with is_system=true.
- In the form, the
kindandkeyfields are disabled β the type and identifier key cannot be changed. - Fields such as
name,audience_scope, and visibility settings can be edited. - Deletion is only possible via the L1/L2 bulk delete, and it is recommended to preserve system boards for operational continuity.
2. Writing Notice / FAQ / General Postsβ
Post management is performed per BoardPost in the Posts RelationManager (PostsRelationManager) of the board detail view. The main fields of BoardPost are as follows.
| Field | Description |
|---|---|
title / body | Title / Body |
excerpt | Summary |
category | Category (used for FAQ category grouping) |
status | draft / published |
is_pinned | Pin to top (shown at the top of the notice list) |
published_at | Publication time |
starts_at / ends_at | Visibility start/end period |
Publication and Visibility Periodβ
The posts visible to members are determined by BoardPost::scopePublished(). A post is exposed only if it satisfies all of the following conditions.
status = publishedpublished_atis empty or at or before the current timestarts_atis empty or at or before the current timeends_atis empty or at or after the current time
In other words, you can schedule a time-limited notice using starts_at / ends_at, and you can pin a post to the top of the notice list using is_pinned.
3. Operating 1:1 Inquiriesβ
Inquiry responses are handled under Customer Inquiries β 1:1 Inquiry (InquiryResource) in the SaaS, Tenant, and Org panels. Since inquiries are created by members, operators cannot create new ones (canCreate() = false).
Hierarchical Visibility (upper organizations view lower inquiries)β
Which inquiries can be viewed is determined by BoardInquiry::scopeVisibleTo() based on the viewer's level.
| Viewer level | Visibility scope |
|---|---|
| L0 / L1 / L2 | All Tenant and SaaS inquiries (global scope) |
| L3βL5 organization operators | Their own inquiries + inquiries with an origin (organization_id) or assignment (assigned_org_id) in their organization subtree (ViewerScopeResolver::orgSubtreeIds()) |
| L6 members | Only their own inquiries (inquiries from colleagues in the same organization are not visible) |
The key point is that an upper-organization operator can view the inquiries of lower organizations. An inquiry has two organization fields.
organization_idβ the member's organization at the time of creation (the basis for the visibility scope)assigned_org_idβ the organization currently handling it (moves according to escalation)
The inquiry list shows the title, author (author.name), organization, assigned organization (assignedOrg.name), status (badge), and the time of the latest reply, and it provides a status filter (open/answered/closed).
Writing Replies (Operator)β
You write replies in the Replies RelationManager (RepliesRelationManager) of the inquiry response screen (EditInquiry).
- When a reply is written, the inquiry status automatically changes to
answeredandlast_reply_atis updated. - Turning on the
is_internaltoggle makes it an internal note. Internal notes are not exposed to members (BoardInquiryReply::scopePublic()returns onlyis_internal=false). - The operator can directly change the inquiry status (
open/answered/closed) in the top form. The title and category are read-only.
Escalationβ
The Escalate action in the header of the response screen (EditInquiry) raises an unresolved inquiry up one level to the parent organization. This action is shown only when config('board.inquiry.escalation_enabled', true) (CORE_BOARD_INQUIRY_ESCALATION) is true.
The behavior is handled by BoardInquiry::escalate().
- It moves
assigned_org_idto the parent organization (organizations.parent_id) of the current handler (assigned_org_id). - If there is no parent (
parent_id = null), it setsassigned_org_idtonullβ this means it has reached the Tenant/SaaS queue (the top level). - After the move, the status is reverted back to
open. - If it is already at the top level (
assigned_org_id = null), it does not move and sends a "top level reached" notification (noorganization_idfallback β to prevent re-escalation).
The escalation action automatically records the hierarchical context in the audit log via the shared logging module (->audited('board.inquiry.escalate')).
4. Usage from the Member's Perspectiveβ
Members use the following pages in the App panel (/app) (shown only when a board is active).
Notices (NoticesPage)β
Members view the published posts of notice boards exposed to their own hierarchy (the entire SaaS + their Tenant + the organization ancestor chain). Pinned posts (is_pinned) come at the top, and clicking a post shows its body in a modal. For XSS prevention, the body is escaped and only line breaks are allowed (nl2br(e($body))).
FAQ (FaqPage)β
Members view the posts of exposed faq boards grouped by category (category). Clicking a post shows its body in a modal.
My Inquiries (MyInquiriesPage)β
Members view only the inquiries they created themselves (user_id = auth()->id()).
- Creating a new inquiry: The member selects an exposed
inquiryboard and enters a title and content to create it. At creation time, bothorganization_idandassigned_org_idare set to the member's organization, so that organization (and its upper organizations) becomes the response entry point. The creation transaction creates one inquiry plus one initial reply (is_internal=false) together. - Replying: When the member opens an inquiry and adds a reply, the status returns to
openandlast_reply_atis updated. Members see only replies excluding internal notes (is_internal=false).
5. Internationalization (i18n)β
All labels and messages of the built-in board are provided in four languages via lang/{locale}/board.php.
| locale | Language |
|---|---|
ko | Korean (default) |
en | English |
ja | Japanese |
zh-CN | Chinese (Simplified) |
The Filament Resources, member pages, and notifications all use __('board.*') translation keys, so menu names (e.g., board.navigation_group_site β "Site Management", board.navigation_group_inquiry β "Customer Inquiries") and guidance text switch automatically according to the user's locale.
Reference: Summary of Key Classesβ
| Component | Class / Location |
|---|---|
| Filament plugin | App\Filament\Board\BuiltinBoardFilamentPlugin (id builtin-board) |
| Board container Resource | App\Filament\Board\Resources\BoardResource (slug site-boards) |
| Post RelationManager | ...\BoardResource\RelationManagers\PostsRelationManager |
| Inquiry Resource | App\Filament\Board\Resources\InquiryResource |
| Inquiry response page | ...\InquiryResource\Pages\EditInquiry (escalation action) |
| Reply RelationManager | ...\InquiryResource\RelationManagers\RepliesRelationManager |
| Member pages | App\Filament\App\Pages\{NoticesPage, FaqPage, MyInquiriesPage} |
| Models | App\Models\{Board, BoardPost, BoardInquiry, BoardInquiryReply} |