P10D-1A — Directus TAC Read Precheck for /knowledge/laws (2026-04-30)
P10D-1A — Directus TAC Read Precheck for /knowledge/laws
Date: 2026-04-30
Scope: Read-only precheck. No code/DDL/DML/permission changes.
Verdict: FAIL — Public (anonymous) Directus role cannot read the four TAC collections required by /knowledge/laws.
1. Gate 0 — Machine identity
| Check | Result |
|---|---|
| Control host | Nguyens-MacBook-Air.local (nmhuyen) |
| Runtime host (SSH contabo) | vmi3080463.contaboserver.net |
| Repo path on VPS | /opt/incomex |
| Containers running | postgres, incomex-directus |
| DB identity | directus/directus ✅ |
Gate 0 PASS — runtime is VPS, DB identity matches expected.
2. Current /knowledge/laws Directus access pattern
File: /opt/incomex/docker/nuxt-repo/web/pages/knowledge/laws/index.vue
Pattern:
- Imports
readItemsfrom@directus/sdk. - Uses
const { $directus } = useNuxtApp(); - Calls
$directus.request(readItems('governance_docs', { ... }))insideuseAsyncData('governance-docs', ...).
Plugin: web/modules/directus/runtime/plugins/directus.ts
- Server (SSR):
createDirectus(serverUrl).with(rest())— noauthentication()layer, no token. SSR fetches go as anonymous / public role. - Client (browser):
createDirectus(/api/directus).with(authentication('session', { credentials: 'include' })).with(rest())— uses session cookie if a user is logged in; otherwise still public.
useAsyncData resolves on the server first, so the effective role for the initial render of /knowledge/laws is the Directus Public role (no token).
3. TAC read test results
All HTTP calls executed on VPS against https://directus.incomexsaigoncorp.vn (same host the Nuxt server uses).
3a. Anonymous (matches /knowledge/laws SSR path)
| Collection | HTTP | Result |
|---|---|---|
tac_publication |
403 | FORBIDDEN — You don't have permission to access collection "tac_publication" or it does not exist. |
tac_publication_member |
403 | Same FORBIDDEN message |
tac_logical_unit |
403 | Same FORBIDDEN message |
tac_unit_version |
403 | Same FORBIDDEN message |
governance_docs (control) |
200 | Returns published rows — confirms current page works because public role has READ on this collection only. |
3b. Admin token (sanity — tables exist and are populated)
| Collection | HTTP | meta.total_count |
Notes |
|---|---|---|---|
tac_publication |
200 | 3 | D35 (27e48995-…), D32, D28 visible. |
tac_publication_member |
200 | 86 | Includes D35 pub_id rows. |
tac_logical_unit |
200 | 86 | Has canonical_address, parent_id, sort_order, section_type. |
tac_unit_version |
200 | 86 | Has title, body, version_number. |
Conclusion: collections exist, schema fields present, data present. The 403s are permission-only, not missing-collection.
3c. Required deep/relation fields probe
Not executed. Anonymous read on parent collection already 403; deep-relation fields (logical_unit_id.*, unit_version_id.*) require READ on the related collections, which are also 403.
4. Permission gap (read-only inspection result)
The Directus Public role currently has READ on:
governance_docs✅
It is missing READ on:
tac_publication❌tac_publication_member❌tac_logical_unit❌tac_unit_version❌
No fields/relations have been verified at the Public role level because the collection-level gate fails first.
5. Required fields for tree/reader
Confirmed available in DB (via admin probe), but not reachable by the Public role:
tac_publication:id, doc_code, version, name, lifecycle_statustac_publication_member:render_order, logical_unit_id (m2o), unit_version_id (m2o)tac_logical_unit:id, canonical_address, parent_id, sort_order, section_typetac_unit_version:id, title, body, review_state, lifecycle_status
6. Verdict
FAIL. The current /knowledge/laws SSR path runs as the Directus Public role and is denied READ on all four TAC collections. PG/render correctness is not the blocker; the Directus permission “key” for the web role is missing.
7. Next action
Do not implement assembly wiring yet. Authorize a Directus admin (UI or API, separate session) to grant the Public role (or a dedicated web_reader policy applied to anonymous + authenticated sessions) READ permissions on:
| Collection | Action | Fields |
|---|---|---|
tac_publication |
read | id, doc_code, version, name, lifecycle_status (consider filter lifecycle_status = 'enacted') |
tac_publication_member |
read | id, publication_id, logical_unit_id, unit_version_id, render_order |
tac_logical_unit |
read | id, canonical_address, parent_id, sort_order, section_type, doc_code |
tac_unit_version |
read | id, logical_unit_id, version_number, title, body, review_state, lifecycle_status |
After permissions are granted, re-run this precheck (anonymous probe must return 200 on all four). Only then proceed to the one-file assembly wiring prompt for web/pages/knowledge/laws/index.vue.
8. STOP
Report uploaded. No implementation performed. No permission changes made.