User Manual + Implementation Spec (Draft / English)
Message to the offshore team (please read first)
Before you start implementing, please validate that you fully understand this specification and are confident you can deliver exactly as described.
If anything is unclear or seems infeasible, stop and ask questions first (do not start with assumptions).
We want to proceed only after you confirm that you can implement this spec as-is.
0. Goal (What this page is for)
The Models page lists the models that are currently managed/used in Dev-Portal.
Users can do two things:
- Create New Model (New)
- Import Existing Model (Import from Odoo metadata via src tables)
This page is intentionally kept simple. If we can implement this page correctly, the overall foundation will be ready.
1. Scope (Must / Not Required)
1.1 Must (Required in this task)
- Display a list of models (base table:
public.portal_model) - Display “custom field count” per model (aggregated from
public.portal_fields) - Provide two actions:
- New: create a model row in
portal_model(ONLY) - Import Existing: call an API that imports model + fields + views from src tables into portal tables
- New: create a model row in
1.2 Not required (Out of scope for now)
- Smart button import (
portal_smart_button) NOT required - Menu import (
portal_menu) NOT required - Odoo screen navigation NOT required
- “Applied/Approved” status reconciliation with Odoo NOT required
(If UI shows such labels, mark them as “not implemented yet” or hide them.)
2. Source of Truth and Data Flow
2.1 Source of Truth
Odoo metadata is continuously synchronized into Dev-Portal “src” tables via RPC.
For this task, assume src tables are always up-to-date and are the single source of truth for import.
public.portal_fields_src(up-to-date via Odoo RPC)public.portal_view_src(up-to-date via Odoo RPC)
2.2 Portal-managed tables (UI reads / API writes)
public.portal_model(one row per model shown in the list)public.portal_fields(field definitions; used for counts and later pages)public.portal_view_common(model-centric common view settings)public.portal_view(view-type specific settings)
3. Data Relationships (Important: 1:1 between model and view_common)
Assumption for this project:
portal_modelandportal_view_commonare 1:1portal_view_commonandportal_vieware 1:N (perview_type)portal_modelandportal_fieldsare 1:N
3.1 ER (simplified)
portal_model (1) ── 1:1 ── portal_view_common (1) ──< portal_view (N)
portal_model (1) ─────────< portal_fields (N)
3.2 Uniqueness constraints assumed by implementation
portal_view_common: one row per model- recommended uniqueness:
UNIQUE (model)
- recommended uniqueness:
portal_view: one row per view type under the same commonUNIQUE (common_id, view_type)(already in the provided DDL)
4. UI Specification — Models Page
4.1 List display
The page displays all records from portal_model.
Each model card (or list row) should show at minimum:
- Model label (display name)
- Model technical name (e.g.,
sale.order) - Model table name (e.g.,
sale_order) - Custom field count (aggregated from
portal_fieldsfor that model) - Notes (optional)
- Updated date (optional)
4.2 Actions / Buttons
Two buttons at the top:
- + New
- Import Existing
Important:
- New and Import Existing are different operations and must be clearly labeled.
- Import Existing must be performed via API only (frontend must not manipulate DB directly).
5. Feature: Create New Model (New)
5.1 Purpose
Register a new model as a Dev-Portal-managed model.
It does NOT require the model to already exist in Odoo.
5.2 Minimal input fields (UI)
model(technical name) — e.g.,x_custom.ordermodel_table— e.g.,x_custom_orderlabelorlabel_i18n.ja_JP— e.g., “Custom Order”notes(optional)
5.3 Database behavior (must)
- Insert exactly one row into
public.portal_model - Do NOT create any related records:
portal_fieldsremains 0 rows for this modelportal_view_commonremains 0 rows for this modelportal_viewremains 0 rows for this model
Result: the model is created as an “empty shell” with no fields or views.
6. Feature: Import Existing Model (Import Existing) — API-driven
6.1 Purpose
Import an already-existing Odoo model into Dev-Portal by reading the latest metadata from src tables and upserting into portal tables.
6.2 Frontend responsibility (must)
Frontend does only:
- User selects/inputs a target model name (e.g.,
sale.order) - Frontend calls the Import API
- On success: refresh list (re-fetch
portal_modeland field counts) - On failure: show error and allow retry
All extraction / mapping / upsert logic is on the API side.
6.3 Import API — expected contract (example)
Endpoint name may differ, but the behavior must match.
- HTTP:
POST /portal/models/import(example) - Header:
Idempotency-Key: <uuid>(required for POST) - Body
{ "model": "sale.order" }
6.4 Import API — required server-side behavior (must)
When importing a model X:
(A) Upsert portal_model (1 row)
- Create or update
public.portal_modelfor modelX
(B) Upsert portal_fields (N rows)
- Read all rows from
public.portal_fields_srcwheremodel = X - Upsert them into
public.portal_fields
(C) Upsert portal_view_common (1 row; model-centric)
- Read rows from
public.portal_view_srcwheremodel = X(likely multiple rows) - Create or update exactly one row in
public.portal_view_commonfor modelX
(D) Upsert portal_view (N rows; per view_type)
- Using the
portal_view_common.idascommon_id, upsert one row perview_type - Key must be
(common_id, view_type)(no duplicates)
Explicitly NOT included (out of scope):
- Smart button import: do not touch
portal_smart_button - Menu import: do not touch
portal_menu
6.5 Idempotency (must)
Importing the same model multiple times must:
- Not create duplicates
- Update existing records via UPSERT
- Keep
portal_view_commonat exactly one row per model - Keep
portal_viewat exactly one row per (common_id, view_type)
6.6 Suggested response payload (example)
Return counts so the UI can show a success message:
{
"status": "ok",
"model": "sale.order",
"upserted": {
"portal_model": 1,
"portal_fields": 128,
"portal_view_common": 1,
"portal_view": 5
}
}
7. Acceptance Criteria (Definition of Done)
This task is considered complete when:
- Models page lists all records in
portal_model - New creates exactly one row in
portal_modeland creates no fields/views - Import Existing calls an API, and the API imports from:
portal_fields_src→portal_fieldsportal_view_src→portal_view_common(1 row per model) andportal_view(per view_type)
- Custom field count updates correctly after import
- Smart buttons and menus are not imported (not implemented)
コメントを残す