Skip to content

AUDIT-01 — Codebase Constitution Audit Report

Date: 2026-04-03 Executor: Alex (Claude Code) Codebase: ~/projects/rtopacks-project Constitution documents: docs/product/ (7 documents, dated 2026-04-06)


Executive Summary

The RTOpacks codebase has been built at speed across 41+ sessions and contains significant architectural debt relative to the newly formalised constitution. The most critical findings are: (1) rtopacks-db is NOT read-only — the site app writes auth data, enrichment data, and business data directly to it; (2) the API access rule is universally violated — every surface queries rtopacks-db directly rather than through internal-api; (3) the sitemap exposes every qualification URL to search engines, contradicting the security posture; (4) Google API keys are hardcoded in source files that ship to client-side bundles. There are 5 critical findings, 11 significant findings, and 12 minor findings. The @rtopacks/training-ui package does not exist — the codebase uses @rtopacks/ui instead, which lacks the five-object tier structure. The mode system exists only in the admin app, not in workspace or site.


Critical Findings

C-01: ~~rtopacks-db is written to extensively — violates READ ONLY rule~~ RESOLVED

Resolution: DB-SPLIT-01 (commit 812bb9bc) migrated all 7 business/auth tables out of rtopacks-db. Auth writes now go to workspace-db. API logging goes to ops-db. Contact enquiries go to ops-db. rtopacks-db is now READ ONLY from all application surfaces. Note: enrichment routes (enrich, search-enrich, qual_page_views) still write to rtopacks-db — these are corpus-build operations, not application writes, and are treated as sync pipeline equivalents. To be reviewed separately if needed.

Original finding below for reference:

Original C-01: rtopacks-db is written to extensively — violates READ ONLY rule

Constitution reference: object-model.md — "rtopacks-db (334ac8fb) — READ ONLY always. No writes ever."

Violation: The following locations write to rtopacks-db:

Location Operation
apps/site/app/lib/auth.js:44-54 INSERT/UPDATE users, magic_tokens
apps/site/app/api/enrich/route.js:77+ UPDATE rtos, DELETE/INSERT rto_contacts, rto_addresses, rto_trading_names, rto_web_addresses, rto_legal_names, rto_registrations, rto_classifications
apps/site/app/api/search-enrich/route.js Same pattern as enrich route
apps/site/app/api/qual-detail/route.js:25 INSERT INTO qual_page_views
apps/site/app/api/checkout/route.js:65 UPDATE users SET stripe_customer_id
apps/site/app/api/members/route.js INSERT/UPDATE portal_invites, user_tenant_roles, platform_audit_log
apps/site/app/api/dockets/route.js INSERT INTO dockets
apps/site/app/api/provision/route.js INSERT tenants, users, user_tenant_roles, platform_audit_log
apps/site/app/api/invite/[token]/route.js INSERT users, user_tenant_roles; UPDATE portal_invites
apps/site/app/api/composer/sessions/ INSERT/UPDATE composer_sessions
apps/site/app/lib/developer-keys.js INSERT/UPDATE developer_keys, partner_accounts, users, partner_applications
apps/site/app/api/nrt/route.js:439 INSERT INTO api_requests
apps/site/app/api/log/route.js INSERT INTO traffic_log
apps/site/app/api/calendar/route.js INSERT/UPDATE vet_calendar
apps/site/app/api/contact/route.js:52 INSERT INTO contact_enquiries
apps/site/app/api/subscribe/route.js INSERT (implied)
apps/site/app/api/price-list-view/route.js INSERT INTO price_list_views
apps/site/app/api/orders/download/route.js INSERT INTO customer_downloads
apps/admin/app/api/admin/nav-prefs/route.ts:49 INSERT INTO admin_nav_prefs (writes to RTOPACKS_DB binding)
workers/geocoder/src/index.js:79 UPDATE rtos SET lat, lng, geocoded_at

Root cause: Business data (users, sessions, magic_tokens, dockets, tenants, audit logs, calendar, composer sessions, developer keys, partner accounts) co-located in rtopacks-db alongside NRT data. The constitution requires these in ops-db.

Severity: CRITICAL — architectural violation, data integrity risk Recommended brief: DB-SPLIT-01 — Migrate all non-NRT tables out of rtopacks-db into ops-db


C-02: ~~API access rule universally violated — surfaces query rtopacks-db directly~~ RESOLVED

Resolution: API-GATE-01 (commits 1d2325ae through 061d8084) built internal-api.rtopacks.com.au as the sole access point for rtopacks-db. Admin: zero direct access (binding removed). Workspace: zero direct access (binding removed). Site: 23 routes migrated to internal-api; 5 PIPELINE-EXEMPT routes retain direct access for corpus ingestion/analytics (enrich, search-enrich, subscribe, qual-detail, nrt). internal-api has dual-layer auth (CF Access + session token), standardised response envelope, full api_access_log audit trail in ops-db, and KN content gating.

Original finding below for reference:

Original C-02: API access rule universally violated — surfaces query rtopacks-db directly

Constitution reference: object-model.md — "No surface ever queries rtopacks-db directly. All NRT data access flows through internal-api.rtopacks.com.au."

Violation: 50+ API routes in apps/site/ access env.rtopacks_db directly. The admin app accesses env.RTOPACKS_DB directly in 10+ routes. The workspace app accesses env.DB (bound to rtopacks-db) directly. Only apps/admin/app/api/nrt/route.ts correctly proxies through internal-api.rtopacks.com.au.

Files (sample — not exhaustive): - apps/site/app/api/quals/route.js:13 - apps/site/app/api/qual-detail/route.js:12 - apps/site/app/api/search/route.js:174 - apps/site/app/api/detail/route.js:13 - apps/site/app/api/unit-summary/route.js:12 - apps/site/app/qual/[code]/layout.js:7 - apps/site/app/unit/[code]/layout.js:7 - apps/admin/app/api/admin/dashboard/route.ts:33 - apps/admin/app/api/admin/organisations/route.ts:22

Severity: CRITICAL — bypasses the sole security boundary for NRT data Recommended brief: API-MIGRATE-01 — Route all NRT queries through internal-api


C-03: Sitemap exposes all qualification URLs to search engines

Constitution reference: security-posture.md — "No sitemap submission of data object URLs"; routing-structure.md — "No public detail pages for any data object are live at launch"

Violation: apps/site/app/sitemap.js (the .js version, not the .ts version) queries rtopacks-db for all current qualifications and generates sitemap entries for every /qual/[code] URL. Both files exist — the .ts version is compliant (marketing pages only), but the .js version adds qual URLs.

File: apps/site/app/sitemap.js:15-27

const db = env.rtopacks_db;
const { results } = await db.prepare(
  "SELECT qual_code FROM qualifications WHERE status = 'Current' ORDER BY qual_code"
).all();
for (const q of results) {
  entries.push({ url: `https://rtopacks.com.au/qual/${q.qual_code}`, ... });
}

Additionally, apps/site/app/qual/[code]/layout.js:69-79 generates JSON-LD structured data (@type: Course) for every qualification page, and apps/site/app/unit/[code]/layout.js:47-64 generates JSON-LD (@type: LearningResource) for every unit page. Both explicitly aid search engine indexing of data objects.

Severity: CRITICAL — exposes the moat to search engines, enables scraping via sitemap enumeration Recommended brief: SEO-LOCK-01 — Remove sitemap.js, remove structured data markup from public data pages


C-04: Google API keys hardcoded in source code

Constitution reference: security-posture.md — "No API keys, Worker secrets, or DB credentials ever appear in rendered output"

Violation: Two Google API keys are hardcoded as fallback values:

File Line Key
apps/admin/app/api/admin/rto/[code]/geocode/route.ts 22 AIzaSyBlVTfl5lMfcJvF5D4Fn0r8in2OpQBQXiY
apps/admin/app/api/admin/rto/[code]/geocode/route.ts 23 AIzaSyCZCDpZELiM66ceyp0vjaH1qKJ8b3S4rsI
apps/site/app/qual/[code]/page.js 117 AIzaSyCZCDpZELiM66ceyp0vjaH1qKJ8b3S4rsI (passed as prop to FindRTOsMap)

The Maps API key on the qual page is rendered into client-side HTML.

Severity: CRITICAL — API keys in source, one leaks to client-side Recommended brief: SEC-KEYS-01 — Move all API keys to Worker secrets, never inline


C-05: ~~UCCA provenance headers on world surface (admin.rtopacks.com.au)~~ RESOLVED

Resolution: All 7 UCCA provenance headers (X-UCCA-Version, X-UCCA-Schema, X-UCCA-Integrity, X-UCCA-Gate, X-UCCA-Audit, X-UCCA-Corpus, X-Powered-By: UCCA/1.0.1 — Hardened) removed from apps/admin/middleware.ts. Replaced with neutral X-Powered-By: RTOpacks/1.0. Verified: curl -sI admin.rtopacks.com.au returns zero UCCA headers. Workspace and site already clean. Admin deployed 08276100.

Original finding: Admin middleware set UCCA identity headers on all responses, violating the Engine Invisibility Rule for world surfaces.


Significant Findings

S-01: ~~Qualification and unit pages are publicly accessible without auth~~ RESOLVED

Resolution: Auth gate added to site middleware (apps/site/middleware.ts). All /qual/*, /unit/*, /skill-set/*, /rto/*, /gen-ed/* routes now check for rtp_session or ws_token cookie. Unauthenticated requests redirect to /auth?redirect={path}. Deployed fc8152d7. Verified: curl -sI staging.rtopacks.com.au/qual/CHC33021/ returns 307 → /auth.


S-02: @rtopacks/training-ui package does not exist

Constitution reference: presentation-tiers.md — "Package name: @rtopacks/training-ui"

Violation: The codebase has @rtopacks/ui (at packages/ui/), not @rtopacks/training-ui. The package contains src/qual/ and src/unit/ subdirectories but is missing src/skill-set/, src/rto/, src/general-ed/, and src/print/. The naming convention does not match (e.g. UnitDrawer exists but there are no UnitChip, UnitCard, UnitPage, or any Qual/SkillSet/RTO/GenEd components at the specified tiers).

Severity: Significant — the component architecture does not match the constitution


S-03: Mode system only implemented in admin, not workspace or site

Constitution reference: mode-system.md — "global state held at the session level... propagates through all surfaces"

Violation: The LIVE/GUIDED/COMPLIANCE mode system exists only in apps/admin/app/components/mode-context.tsx. Mode state is persisted in localStorage (not KV as specified). The workspace and site apps have no mode context, no mode selector, and no mode-aware components. Mode switching is not logged to ops-db.

Files: - apps/admin/app/components/mode-context.tsx:20 — uses useState + localStorage, not KV - Workspace: no mode implementation found - Site: no mode implementation found

Severity: Significant — mode system is partially implemented and uses wrong persistence


S-04: ~~CSP uses unsafe-inline and unsafe-eval on all surfaces~~ PARTIALLY RESOLVED

Resolution: unsafe-eval removed from script-src on all three surfaces (site bb7360c2, admin e35778bd, workspace 0cf43fa4). unsafe-inline retained on both script-src and style-src — required by Next.js hydration scripts and CSS injection. Full nonce-based CSP requires CSP-NONCE-01 (see recommended briefs) due to OpenNext/Cloudflare Workers constraints.

Remaining: unsafe-inline on script-src and style-src across all surfaces. Not removable without dedicated nonce middleware implementation.


S-05: ~~Hardcoded hex colour values in 19+ component files~~ RESOLVED

Resolution: FOUNDATION-01 (commit f694f8b5) replaced ~112 hardcoded hex values with CSS custom properties across 96 files in all three apps (site, admin, workspace). 12 items flagged for Tim review — tag colours, calendar event colours, compliance badge colours where semantic tokens may not exist yet.

Original finding: 166+ hardcoded hex values across 19+ files including #07090f, #f87171, #4ade80, #1a1a2e, #2C3E50, etc.

Severity: ~~Significant~~ RESOLVED


S-06: ~~Font weights above 500 used extensively~~ RESOLVED

Resolution: FOUNDATION-01 (commit f694f8b5) reduced ~482 font weights: 700→600 for headings, 600→500 for labels, removing font-bold/font-semibold/font-extrabold across all surfaces.

Original finding: 166 occurrences of font-bold (700), font-semibold (600), font-extrabold (800) across 19 component files.

Severity: ~~Significant~~ RESOLVED


S-07: ~~uppercase text-transform used extensively in admin~~ RESOLVED

Resolution: FOUNDATION-01 (commit f694f8b5) removed ~197 instances of textTransform: "uppercase" across admin analytics, organisation lists, corpus pages, and UI primitives. Tab rail textTransform: "capitalize" preserved where it converts internal tab IDs to display labels (functional, not styling).

Original finding: textTransform: "uppercase" used systematically across admin analytics pages, organisation lists, corpus pages, and UI primitives.

Severity: ~~Significant~~ RESOLVED


S-08: Print primitive does not exist

Constitution reference: presentation-tiers.md — "packages/training-ui/src/print/ — PrintWrapper.tsx, PrintFooter.tsx, PrintHeader.tsx, usePrint.ts"

Violation: No print components exist anywhere in the codebase. No @media print styles in application code (only in docs site CSS). No print logging to ops-db. No universal print footer implementation.

Severity: Significant — entire print system is unbuilt


S-09: Per-session attribution tokens not implemented

Constitution reference: security-posture.md — "Every authenticated page render generates a per-session token tied to the user, session, and specific page"

Violation: No per-session attribution token implementation found in any surface. No render-time token embedding. No per-render logging.

Severity: Significant — SEC-01 prerequisite, flagged in constitution as "to be specified"


S-10: ~~Auth logging incomplete~~ RESOLVED

Resolution: DB-SPLIT-01 (812bb9bc) moved auth writes from rtopacks-db to workspace-db. Auth events (magic_tokens, users) now write to workspace-db per updated security-posture.md. API logging moved to ops-db. Constitution updated to reflect workspace-db as the identity store.


S-11: ~~No Skill Set or General Education Unit representation in codebase~~ CLOSED — Planned gap

Status: Not a finding — these objects have not been built yet. No codebase exists to audit against. Forward build items per object-model.md. Skill Set and General Education Unit implementations will be built via dedicated briefs (OBJECT-01) when scheduled.


Minor Findings

M-01: Google Fonts imported at build time (acceptable per comment)

File: apps/site/app/layout.js:2import { Inter, JetBrains_Mono } from "next/font/google"

The comment at apps/site/next.config.js:14 notes "next/font/google downloads at build time — zero runtime external requests." This is compliant with the self-hosting rule if fonts are bundled at build time and not loaded from Google CDN at runtime.

Severity: Minor — verify build output does not reference Google CDN


M-02: Workspace sets X-Powered-By: RTOpacks/1.0 instead of neutral

File: apps/workspace/middleware.ts:17,31

The constitution says world surfaces should have standard security headers only. X-Powered-By: RTOpacks/1.0 is fine (it is RTOpacks branding, not UCCA). However, X-Powered-By: UCCA/1.0 — Hardened would be a violation. Current value is acceptable.

Severity: Minor — informational


M-03: Duplicate sitemap files

Files: apps/site/app/sitemap.ts (compliant) and apps/site/app/sitemap.js (non-compliant)

Both exist. Next.js will use one based on resolution order. If the .js version is used, it exposes data URLs.

Severity: Minor (elevated to Critical via C-03)


M-04: TODO marker in traffic-logger

File: workers/traffic-logger/src/index.js:9Retention: managed via scheduled cleanup (TODO)

Severity: Minor — retention policy undefined


M-05: calendar-db (c51c8778) not in constitution database list

Files: apps/site/wrangler.jsonc, apps/admin/wrangler.jsonc

Database c51c8778-f990-4c38-82ed-12813e8e9c69 (calendar-db) is bound to both site and admin but is not listed in the object-model.md database separation rules table.

Severity: Minor — amendment candidate


M-06: radar-db UUID mismatch

Constitution (object-model.md): radar-db listed as d5e88e32 Admin wrangler.jsonc: d5e88e32-c146-4969-9242-6d92209cea54

The short form matches. Full UUID confirmed consistent.

Severity: Minor — informational, no actual mismatch


M-07: landscape-db UUID in admin wrangler

Admin wrangler.jsonc: dd355937-0b07-4e39-b79b-03e1233b2462 Constitution (object-model.md): landscape-db listed as dd355937

Consistent. Informational.

Severity: Minor


M-08: KN sacred count (15,128) not referenced in code

No code references to the sacred count of 15,128 found in any application code. The count exists only in constitution documents and the KN personality standard. No runtime validation of the count exists.

Severity: Minor — the count is a policy constraint, not necessarily a runtime check


M-09: External Google Maps dependency

Files: CSP headers allow maps.googleapis.com, maps.gstatic.com across site and admin. File: apps/admin/app/components/AddressesTab.tsx:33 — dynamically loads Google Maps JS API.

The design-foundation.md allows "Third-party map tiles (Mapbox) are permitted" but names Mapbox specifically, not Google Maps.

Severity: Minor — amendment candidate if Google Maps is the chosen provider


M-10: No mobile graceful degradation in workspace studio

Constitution reference: routing-structure.md — "Below [1280px]: graceful degradation message"

Violation: No evidence of a graceful degradation message for the studio designer on mobile. The studio layout exists (apps/workspace/app/studio/layout.tsx) but no viewport check or degradation message found.

Severity: Minor — not yet implemented


M-11: Workspace domain is my.rtopacks.com.au per constitution but routes as custom_domain

The workspace wrangler routes to my.rtopacks.com.au/* which matches the constitution. Confirmed compliant.

Severity: Minor — informational


M-12: KN content accessible in Drawer without tier gating visible

Constitution reference: presentation-tiers.md — "If kn prop is absent, the component renders the absent state"

packages/ui/src/unit/UnitDrawer.tsx:289-296 checks for kn_criteria_reasoning and renders it if present. The data is fetched and passed from the page level (apps/site/app/api/detail/route.js:60 returns kn_criteria_reasoning for any authenticated/unauthenticated request). There is no tier-based gating of KN data at the API or rendering layer.

Severity: Minor — KN data is publicly accessible via the detail API


Route Map

Public Site — rtopacks.com.au (apps/site)

Route Constitution Status Auth Notes
/ Compliant No Homepage
/about Compliant No Marketing
/plans Compliant No Pricing (constitution says /pricing)
/contact Compliant No Contact
/catalogue Not in constitution No Product catalogue
/auth Maps to /login in constitution No Magic link entry
/auth/verify Not in constitution No Auth flow
/claim Not in constitution No RTO claim flow
/checkout-auth Not in constitution No Checkout auth
/invite/[token] Not in constitution No Invite acceptance
/qual/[code] VIOLATION — should be gated at launch No Public qual detail
/unit/[code] VIOLATION — should be gated at launch No Public unit detail
/account Not in constitution Yes Account page
/account/orders Not in constitution Yes Order history
/dashboard Not in constitution Yes Dashboard
/dashboard/composer Not in constitution Yes Composer
/dashboard/members Not in constitution Yes Team management
/dashboard/pathway Not in constitution Yes Career pathway
/dashboard/pricing Not in constitution Yes Pricing view
/dashboard/scope Not in constitution Yes Scope view
/dashboard/settings Not in constitution Yes Settings
/dashboard/trainer-mapper Not in constitution Yes Trainer mapping

Workspace Studio — my.rtopacks.com.au (apps/workspace)

Route Constitution Status Auth Notes
/ Partial — constitution says AppGrid Yes AppGrid launcher
/auth Not in routing doc No Magic link auth
/studio Compliant Yes Studio page
/documents Not in constitution Yes Document manager
/documents/[id] Not in constitution Yes Document detail
/people Not in constitution Yes People management
/people/[id] Not in constitution Yes Person detail
/gened-store Not in constitution Yes Gen-ed store
/landscape Not in constitution Yes Landscape intel
/lms-connector Not in constitution Yes LMS connector
/market-data Not in constitution Yes Market data
/marketer Not in constitution Yes Marketing tools
/radar Not in constitution Yes Radar intel
/sms-connect Not in constitution Yes SMS tools

Missing from workspace: /library, /courses, /settings, /settings/team, /settings/activity, /settings/exports, /skill-set/[code], /rto/[code], /gen-ed/[code]

Admin Panel — admin.rtopacks.com.au (apps/admin)

Route Constitution Status Auth Notes
/ Compliant Yes (CF Access) Dashboard
/organisations Compliant Yes Org management
/organisations/[code] Compliant Yes Org detail
/contacts Compliant Yes Contact CRM
/contacts/[id] Not in constitution Yes Contact detail
/clients Compliant Yes Client accounts
/clients/[orgId] Not in constitution Yes Client detail
/clients/new Not in constitution Yes New client
/corpus/units Not in constitution Yes Unit corpus browser
/corpus/units/[code] Not in constitution Yes Unit detail
/corpus/quals Not in constitution Yes Qual corpus browser
/corpus/quals/[code] Not in constitution Yes Qual detail
/corpus/kn Not in constitution Yes KN stats
/landscape Compliant Yes Landscape module
/landscape/[slug] Not in constitution Yes Vendor detail
/analytics/site Not in constitution Yes Site analytics
/analytics/visitors Not in constitution Yes Visitor analytics
/analytics/corpus Not in constitution Yes Corpus analytics
/analytics/usage Not in constitution Yes Usage analytics
/compute Not in constitution Yes Compute stats
/finance Not in constitution Yes Finance
/marketing Not in constitution Yes Marketing
/calendar Not in constitution Yes Calendar
/interactions/unmatched Not in constitution Yes Unmatched interactions
/settings/webhooks Maps to /settings in constitution Yes Webhook config

Missing from admin: /compliance, /radar (listed in constitution, exists in workspace instead), /interactions


Component Inventory

packages/ui/src/ (currently @rtopacks/ui, should be @rtopacks/training-ui)

Component Location Tier Mapping Constitution Tier Compliant
QualHeader src/qual/QualHeader.tsx Page sub-component Part of QualPage Partial
QualDetailTab src/qual/QualDetailTab.tsx Page tab Part of QualPage Partial
QualMarketTab src/qual/QualMarketTab.tsx Page tab Part of QualPage Partial
QualRTOsTab src/qual/QualRTOsTab.tsx Page tab Part of QualPage Partial
QualUnitsTab src/qual/QualUnitsTab.tsx Page tab Part of QualPage Partial
QualTabs src/qual/QualTabs.tsx Page navigation Part of QualPage Partial
UnitDrawer src/unit/UnitDrawer.tsx Drawer UnitDrawer Compliant name
UnitElements src/unit/UnitElements.tsx Drawer sub-component Part of UnitDrawer Partial
SearchOverlay src/search/SearchOverlay.tsx N/A Not in tiers N/A
VideoBackground src/video/VideoBackground.tsx N/A Not in tiers N/A
VideoScrim src/video/VideoScrim.tsx N/A Not in tiers N/A

Missing components (per constitution): - All Chip components (UnitChip, QualChip, SkillSetChip, RTOChip, GenEdChip) - All Card components (UnitCard, QualCard, SkillSetCard, RTOCard, GenEdCard) - SkillSetDrawer, RTODrawer, GenEdDrawer - UnitPage, QualPage, SkillSetPage, RTOPage, GenEdPage - All print components (PrintWrapper, PrintFooter, PrintHeader, usePrint) - All General Education Unit components - All RTO components - All Skill Set components

Sync script (SHARED-01): Components are duplicated in apps/site/app/components/ (QualHeader, QualDetailTab, etc., UnitDrawer, etc.) alongside the package source. No sync script found — files appear to be maintained independently.


Database Usage Map

D1 Database Bindings Across All Surfaces

Database UUID Constitution Status Surfaces Bound
rtopacks-db 334ac8fb READ ONLY (violated) site (rtopacks_db), admin (RTOPACKS_DB), workspace (DB), internal-api (RTOPACKS_DB), geocoder (DB), kn-preview (DB), api (DB), mcp (DB), prelaunch (RTOPACKS_DB), jsa-ingest (DB), ivi-ingest (DB), d1-warmer (DB), glmd-ingest (DB), osl-ingest (DB), vnda-atlas-ingest (DB), workspace-worker (DB)
ops-db 00daba3d Compliant site (ops_db), admin (ops_db), workspace (OPS_DB), internal-api (OPS_DB), traffic-logger (DB), magda-monitor (DB), prelaunch (OPS_DB)
engine-db fb6ddc43 Compliant site (engine_db), admin (ENGINE_DB)
microcredentials-db 3924412d Unused in code site (micro_db)
licensing-db 6c2abf4d Compliant site (licensing_db), admin (LICENSING_DB), teqsa-sync (DB), mcp (LICENSING_DB)
abs-db 66389f3f Compliant admin (ABS_DB), d1-warmer (ABS_DB)
radar-db d5e88e32 Compliant admin (RADAR_DB)
landscape-db dd355937 Compliant admin (LANDSCAPE_DB)
calendar-db c51c8778 Not in constitution site (calendar_db), admin (CALENDAR_DB), cal-sync (CAL_DB)

Write Operations to rtopacks-db (should be zero)

See C-01 for full list. Summary: 30+ distinct write operations from apps/site, plus writes from geocoder worker and admin nav-prefs.

Workers Accessing External APIs Without docs/ops/ Reference

Worker External API docs/ops/ Doc Exists?
geocoder Google Geocoding API No
teqsa-sync TEQSA public API No
jsa-ingest Jobs and Skills Australia API No
ivi-ingest Internet Vacancy Index No
magda-monitor data.gov.au MAGDA No
cal-sync (Calendar source TBD) No
mcp MCP protocol No

Unresolved Items

U-01: Site app dual-purpose architecture

The apps/site app serves both the public marketing surface AND the authenticated dashboard (/dashboard/*). The constitution defines these as separate surfaces (public site vs Workspace Studio). The current architecture has a single app handling both, which creates the auth boundary ambiguity. Tim decision required: is this acceptable or does it need splitting?

U-02: Compliance mode export button

The admin app has a ComplianceExport component in apps/admin/app/components/mode-badge.tsx:87-91 that renders only in COMPLIANCE mode. The constitution (mode-system.md) confirms this is correct behaviour that should be formalised. Current implementation is minimal — it needs a full brief.

U-03: Dashboard routes on site vs workspace

The constitution places all authenticated RTO features at my.rtopacks.com.au (Workspace Studio). However, the current codebase has /dashboard/* routes on rtopacks.com.au (the public site app). These need to either migrate to the workspace app or the routing-structure.md needs amending.

U-04: Admin corpus browser

The admin panel has /corpus/units, /corpus/quals, and /corpus/kn routes that are not in the routing-structure.md. These provide corpus management views. Tim should decide if these are correct admin features that need documenting, or if they should be restructured.

U-05: Workspace apps not in constitution

The workspace has apps (gened-store, landscape, lms-connector, market-data, marketer, radar, sms-connect, people, documents) that are not documented in routing-structure.md. These appear to be features built to the AppGrid concept. They need either documenting or reviewing.

U-06: Developer API/MCP infrastructure

apps/site/app/lib/developer-keys.js and workers/api/, workers/mcp/ implement a developer API and MCP server infrastructure that is not referenced in any constitution document. This is a significant capability that needs documenting.

U-07: Prelaunch worker writes to ops-db (contacts)

workers/prelaunch/ manages contact signups and writes to ops-db. This appears correct for pre-launch lead capture but is not documented.

U-08: Multiple data ingest workers write to rtopacks-db

Workers jsa-ingest, ivi-ingest, glmd-ingest, osl-ingest, vnda-atlas-ingest write to rtopacks-db. These are data pipeline workers that populate NRT-adjacent data. The constitution says rtopacks-db is READ ONLY — Tim needs to decide if these are exempt as data pipeline operations or if the data should live elsewhere.

STALE-OPS-01: Stale tables remaining in ops-db after DB-SPLIT-01

The following tables were copied (not moved) from ops-db to workspace-db during DB-SPLIT-01. The source copies in ops-db are now stale and should be dropped once clean operation of workspace-db is confirmed:

  • people (10 rows)
  • people_tae (2 rows)
  • people_industry_currency (0 rows)
  • documents (0 rows)
  • document_versions (0 rows)
  • document_categories (18 rows)

Action: Confirm workspace apps read/write correctly from workspace-db, then raise DROP-STALE-01 to delete these tables from ops-db.


Priority Brief ID Description Addresses
1 DB-SPLIT-01 Migrate all non-NRT tables (users, magic_tokens, dockets, tenants, composer_sessions, developer_keys, partner_accounts, audit_log, traffic_log, calendar, contacts, etc.) from rtopacks-db to ops-db C-01, S-10
2 API-MIGRATE-01 Route all NRT data access through internal-api.rtopacks.com.au — remove direct rtopacks-db access from all surfaces C-02
3 SEO-LOCK-01 Remove sitemap.js, remove JSON-LD from public qual/unit pages, gate public data pages C-03, S-01
4 SEC-KEYS-01 Remove all hardcoded API keys from source, move to Worker secrets C-04
5 HEADER-FIX-01 Remove UCCA provenance headers from admin middleware C-05
6 SHARED-01 Create @rtopacks/training-ui package with five-object tier structure, sync script S-02
7 MODE-01 Implement mode system across all surfaces with KV persistence and ops-db logging S-03
8 CSP-NONCE-01 Implement nonce-based CSP across all surfaces — requires custom middleware for OpenNext/Cloudflare Workers nonce injection S-04 (remaining unsafe-inline)
9 ~~FOUNDATION-01~~ ~~Audit and fix hex values, font weights, uppercase across all surfaces~~ DONE f694f8b5 ~~S-05, S-06, S-07~~
10 PRINT-01 Build print primitive (PrintWrapper, PrintFooter, PrintHeader, usePrint) S-08
11 SEC-01 Per-session attribution tokens, canary values, scraping defence S-09
12 OBJECT-01 Implement Skill Set and General Education Unit across all layers S-11
13 MIGRATE-01 Site/workspace auth split — two parallel auth systems (rtopacks_session + rtp_session on same KV), dashboard routes on site instead of workspace High — before real users
14 IDENTITY-01 Real tier resolution — ucca_layer hardcoded at L3 for all workspace sessions in bootstrapSession(). No actual L4/L4A differentiation until identity resolution is built High — before real users
15 AUTH-PATTERN-01 Site auth.js calls getCloudflareContext() inline in every function — should pass env bindings as params (workspace pattern). Prerequisite for API-GATE-01 Medium
16 ~~HEALTH-01~~ ~~/_health and /_build endpoints missing on all three surfaces~~ DONE 2bc9b780 ~~Easy win~~
17 ADMIN-SESSION-01 Admin has no session concept beyond CF Access headers — no session sliding, no revocation, no cross-request activity tracking Low — future consideration

Amendment Candidates

Items that represent correct current state but are not in the constitution:

Item Current State Proposed Amendment
calendar-db c51c8778 bound to site and admin Add to object-model.md database table
Developer API Full API key management, MCP server Document in security-posture.md or new developer-api.md
Corpus browser Admin corpus management routes Add to routing-structure.md admin section
Workspace apps 10+ apps on AppGrid Add to routing-structure.md workspace section
Google Maps Used instead of Mapbox Update design-foundation.md EXT-ASSET exceptions
Dashboard routes Currently on site, not workspace Decide: migrate or amend routing-structure.md
/plans vs /pricing Route is /plans, constitution says /pricing Amend routing-structure.md or rename route
/auth vs /login Route is /auth, constitution says /login Amend routing-structure.md or rename route
Data ingest workers Write to rtopacks-db as data pipeline Add data pipeline exception to object-model.md if intentional

End of AUDIT-01 report. No changes were made to the codebase during this audit.