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 |
settings.engagement.view_count_visibility | View-count audience (admin/member/public/hidden) | public |
settings.engagement.likes_enabled | Enable the like button on post details | false |
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).
View Count Visibility and Likesβ
A view is recorded whenever a human opens a readable post detail, regardless of whether the number is visible.
hidden hides the number; it does not stop recording. Admin management surfaces and known bots are excluded, and
the same browser session and post are counted only once during the default 30-minute window. Raw IP/UA values and
per-user reading histories are not stored.
| View-count setting | Who can see the number |
|---|---|
Admin only (admin) | Authorized post/board management surfaces |
Members only (member) | Authenticated users on any readable member or public detail |
Public (public) | Admins, authenticated members, and guests on readable public details |
Hidden (hidden) | Hidden everywhere while recording continues |
Disabling likes hides both the button and the count, and direct state/toggle requests return 404. Even when enabled for a board, the button remains hidden if the site-wide reaction feature is disabled. Guest behavior follows the site-wide Allow guest likes setting. Inquiry boards always force view counts hidden and likes disabled.
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 |
view_count | Accumulated detail views (not directly editable by operators) |
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.
The management list shows numeric view counts only when the board setting is admin or public. In mixed-board
lists, rows that are not allowed show β. Sorting, searching, and filtering are intentionally unavailable so hidden
values cannot be inferred.
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. The detail flow revalidates read access, records the view, and displays the view count and like button according to the board settings. 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 uses the same view-recording and display contract as notices.
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} |
| View tracking | App\Services\BoardPostViewTracker |
| Read boundary | App\Support\SiteBoardPostAccess |
| Like adapter | App\Support\BoardPostReactionResolver β Core ReactionSubjectRegistry |
| Shared display | <x-board-post-engagement> |