• Editorial pass per user direction: stop justifying the architecture.
    For every "why this design works" passage, name the costs the design
    imposes — not as a parenthetical aside but as substantive critical
    analysis. Each major architectural-claim page now carries an explicit
    drawbacks/costs section.
    
    Pages revised:
    
    concepts/thesis.md
    - "The reward" → "What the design enables (and what each enabler still costs)":
      for each promised benefit (single codebase, PMs evolve without
      engineering, customisations layered cleanly), name the limit. Added
      closing observation that data-driven design redistributes complexity
      to people and tools the framework can't compile-check.
    - "When it breaks down": rewrote to call out that "bypassing the
      framework" via 18 customer dirs makes the data-driven thesis
      partial, not complete.
    
    concepts/semantic-fk.md
    - "Why xly disabled FKs": added critical analysis. Both reasons
      could be addressed surgically; the chosen "no FKs anywhere" is the
      trade for DB-enforced integrity, paid every day the system runs.
    
    concepts/master-slave.md
    - "Slave naming caveat": stop framing retention as wise pragmatism.
      The naming was a poor choice; preservation has a real ongoing cost.
    
    concepts/modules-forms-vtables.md
    - "Three nouns, one engine": the universal dispatch path concentrates
      3,500+ lines + edge cases + special-case hardcodes in one class.
      Naming the trade.
    
    concepts/multi-tenancy.md
    - "How the design scales" → "How the design scales — and where it
      doesn't": shared schema = shared contention; tenant-filter index
      discipline; no physical hard-delete; rigid (sBrandsId,
      sSubsidiaryId) tenancy unit.
    
    concepts/customization-channels.md
    - Soften "90%+ should live here" claim — that's an aspirational
      target, not a measured fact. The 18 customer override directories
      are evidence the channel-2 demand is non-trivial.
    
    concepts/api-surface.md
    - "Why three tiers, not one" → "Why three tiers (and what splitting
      them costs)": three WARs to deploy, duplicate code, no shared
      session, three reverse-proxy entries. Note the alternative
      (single-WAR with package boundaries) and what that would cost
      vs gain.
    
    reference/maintainer/proc-dispatch.md
    - "Why dynamic proc dispatch matters": added five concrete costs
      (no compile-time check, no type safety, no call-site discoverability,
      no static analysis, broken stack traces). Reframed: dynamic
      dispatch made it cheap to keep adding procs, which made the pile
      grow, which made the pile harder to audit.
    
    reference/maintainer/cache-invalidation.md
    - New "Drawbacks of this design" section: confusing co-named systems,
      eviction in same transaction as write (silent corruption on
      Redis outage), allEntries=true blunt eviction, no batching,
      direct DB writes bypass everything. Also fixed the "if cache is
      local" hedge in section 3 (we've now empirically confirmed Redis-
      backed, so cache is shared).
    
    reference/maintainer/bi-engine.md
    - New "Drawbacks of the homebrewed approach" section: every chart
      needs a SQL author, charts run heavy SQL on OLTP DB, no semantic
      consistency between charts, no drill-down, customer-divergent KPI
      logic. Also dedup'd the duplicated "What this is not" section.
    
    reference/maintainer/sql-templates.md
    - "Why this is a 'template' library and not a code generator" →
      added costs: no enforcement, no regeneration, no template-origin
      tracking, customer overrides drift from scaffold. The 1,687 procs
      the schema carries are the evidence that "discipline rather than
      enforcement" doesn't fully hold.
    
    reference/maintainer/activiti.md
    - "Why this design works for xly's audience" → "Why xly avoided
      Activiti — and what that costs": scattered workflow logic, no
      central audit trail, no parallel-branch/reassignment, invisible
      flow-graph evolution, idle Activiti engine paying boot cost
      anyway.
    - "Why xly bothered with Activiti at all" → "Why xly bothered with
      Activiti — and whether it was worth it": named the costs (second
      engine, second schema, second auth surface, modeler UI to learn)
      and the damning fact that on this dev DB the engine is idle. A
      future cleanup could plausibly remove Activiti entirely.
    
    reference/maintainer/runtime.md
    - New "What 'universal CRUD' means in practice" section: 3,500-line
      single-point-of-failure class, no type system on Map<String,Object>,
      poor discoverability ("what endpoints write to table X" is
      unanswerable). The trade: adding a module is essentially free,
      touching the runtime essentially never is.
    - Updated cache-invalidation cross-link to drop the "open question"
      hedge (now empirically resolved).
    
    slices/04-custom-field.md
    - "Why it works without code changes" → "Why it works without code
      changes — and what that costs": merge runs on every request,
      three near-empty tables on every schema, display-only extension
      (real persisted fields still need ALTER TABLE), debuggability
      requires diffing 3 overlay tables.
    
    slices/05-customer-sql-override.md
    - Added drawbacks: no version control on the deployed body, no
      type-safety bridge, compounds the BI problem. Reframed the
      "right rule of thumb": 18 customer override directories suggest
      the channel-2 demand is structural, not exceptional — that's
      evidence the metadata model isn't expressive enough, not a
      celebration of the escape hatch.
    
    slices/06-hardware.md
    - "The cleanest story xly tells about an awkward problem" →
      removed the "cleanest" framing. Added costs of "DB as the only
      contract": no backpressure, no request/response, bridge-side
      state invisible to the framework, three layers of polling
      multiply latency, hardest code (byte protocols) gets least CI.
      A real-time-aware architecture would use streaming end-to-end;
      xly's choice trades latency, observability, flow control for
      operational simplicity. Liveable for press tempo, not for
      faster shop-floor signals.
    zichun authored
     
    Browse Code »

  • Plan: /Users/reporkey/.claude/plans/noble-tumbling-sparkle.md
    
    Inventory: 33 hedge entries / open verification items across 12 hand-
    written pages, clustered into 5 groups by why-they're-not-verified.
    
    Cluster A — closed inline by reading source / running DB queries:
    
    - slices/02-multi-tenancy item 1: edition gating is **not** sVersionFlowId
      → sisversionflow. Verified: `grep sVersionFlowId xly-src --include='*.java'
      --include='*.xml'` returns ZERO mapper hits. The actual filter is
      `MenuChildServiceImpl.getBuMenuSql` line 64: `AND m.sId in
      (#{sVersionFlowId... wait sVerifyLicense})`. sVerifyLicense is sourced
      from the TrueLicense-bound `VerifyLicense.getModelAllList()` and
      injected via xlyApi RequestAddParamUtil:50 or controller-level param
      assembly. sVersionFlowId/Code are catalogue tags, NOT runtime gates.
      Wiki body of "How modules are filtered per edition" rewritten.
    - slices/02 item 2: closed; cross-link to the activiti.md rewrite that
      documents Activiti is wired-but-idle.
    - slices/02 item 3: session→tenant chain mapped:
      AuthorizationInterceptor.preHandle → RedisTokenManager.getToken
      (AES-decrypts bearer, checkToken validates Redis at <sLoginType><userId>)
      → @CurrentUser via CurrentUserMethodArgumentResolver →
      RequestAddParamUtil.addParams injects 16 keys.
    - slices/04 item 3: bVisible semantics closed.
      BusinessGdsconfigformsServiceImpl.java:413-433 — customslave row
      matches base by sControlName/sName, REPLACES base. Lines 446-468 —
      user-overlay then explicitly sets bVisible=false at line 464 when
      user-row hides the field. Hides at either layer; scope differs
      (per-tenant vs per-user).
    - slices/05 item 1: DbToDbServiceImpl is inter-DB sync (getData/
      getDataDetail/etc. over Druid+JDBC), NOT a script-applier.
      `grep "script/客户" xly-src --include='*.java'` returns zero. Manual
      application via mysql CLI confirmed.
    - slices/06 item 2: PlcScheduledTasks ships two @Scheduled cron methods
      (`0/30 * * * * ?` line 74, `0/1 * * * * ?` line 105). Per-profile
      tuning is parameter-side, not cron-side.
    - slices/06 item 3: xlyRxtx git history — added in commit daf581311
      ("1、添加串口功能"), commented out in cleanup branch for builds where
      serial isn't needed. xlyPlc runs without RXTX on TCP/Ethernet press
      models; serial-only models would re-enable.
    - builder/define-vtable item 1: 11 of 307 sTbName values (3.6 %) don't
      resolve to a base table. Breakdown: 4 point at views (viw_*),
      3 at procs (Sp_*), 4 at case-drift / dropped tables.
      Audit query embedded.
    - builder/define-vtable hedge: real worked example added — `包装方式 /
      SisPacking` with 10 slave columns mapped to physical columns.
    
    Cluster B — closed via live BACK browser session:
    
    - slices/04 item 1: 界面显示内容配置 (gdsmodule.sId=11, /jmnrpz)
      renders three form-master panels. Third panel
      (sId=19211681019715596285250620, sTbName=gdsconfigformcustomslave)
      is the customslave editor. Verified live via clicking the menu and
      inspecting the GET /business/getBusinessDataByFormcustomId call.
    
    Cluster D — left in place with "Deferred (needs populated DB)" admonition:
    
    - slices/03 item 1 (view-with-print-template): no view-backed forms
      with a sysreport row — DB query returns 0.
    - slices/04 item 4 (real customslave example): COUNT(*) = 0.
    - slices/07 stub (active workflow): act_re_procdef = 0; bCheckflowCheck
      hard-disabled regardless.
    - builder/attach-workflow stub: same — recipe is code-derived
      hypothesis, not live-verified.
    
    Cluster E — left in place with "Deferred (outside repository)" admonition:
    
    - slices/06 item 1 (wire protocols): vendor docs, not source.
    - deployment.md "Open: production URL routing": nginx config in
      deployment ops, not the codebase.
    
    Cluster F — converted to "Future-work backlog" callouts:
    
    - slices/03 hedge "future revision should pick a module with print
      template": demoted to a future-work callout adjacent to the open
      item.
    - slices/05 items 2 & 3: re-cast as "Future-work backlog item — not a
      verification claim" with the workable command/mitigation noted.
    - concepts/customization-channels line 66: rephrased — the choice is
      about *runtime divergence visibility in source control*, not
      maintainer opinion.
    
    Bonus closure:
    - slices/03 item 3 (tenant-leaky views): DB audit returns 19 of 305
      viw_* lacking sBrandsId (~6.2 %). Embedded the SQL + the count.
    - slices/04 line-41 hedge ("needs verification by clicking through
      BACK"): replaced with the verified mapping from item 1.
    
    After-state: of the original 33 entries:
    - 19 newly closed with evidence,
    - 4 left as deferred-because-DB-state with concrete blocker query,
    - 2 left as deferred-because-outside-repo with concrete blocker note,
    - 4 demoted to "Future-work backlog" callouts,
    - 4 already closed in earlier passes.
    
    Build verified `mkdocs --strict` green.
    zichun authored
     
    Browse Code »
  • Third commit closing high-value gaps the user flagged in the
    verification plan.
    
    Cross-node cache coherence — LOCKED EMPIRICALLY:
    - Connected to live Redis at 118.178.19.35:16379 db=0.
    - 233 of 267 keys use Spring's `<cacheName>::<key>` separator.
    - Confirmed key shapes match @Cacheable SpEL specs:
        businessGdsconfigformsServiceGetFormconstData::{...}  (37 entries)
        gdsmoduleById::gdsmoduleById_<sBrandsId>_<sSubsidiaryId>_<sLanguage>  (2 entries)
    - Conclusion: Spring's RedisCacheManager IS the active CacheManager.
      @CacheEvict on any node clears the shared Redis store; cross-node
      coherence works without any JMS involvement. Removed the "open
      question" hedge in cache-invalidation.md.
    
    New page — Metadata-management services (xlyManage):
    - Closes the biggest documentation gap surfaced by Pass C2.
    - Catalogs the 8 large Gds*ServiceImpl classes (878+729+555+489+
      362+319+243+221 = ~3,800 lines of metadata-CRUD logic) plus
      CommonServiceImpl (56) and SysbrandsServiceImpl (125).
    - Documents the universal five-method shape every Gds*Service
      follows (get/getBysId/add/update/delete) and how it pairs with
      the corresponding Gds*Controller in xlyEntry/.../systemweb/.
    - Maps each service to its BACK admin screen.
    - Notes the cache-invalidation hookpoint (synchronous
      BusinessCleanRedisData.delCleanRedisData* on commit).
    - Added to mkdocs nav under Reference (Maintainer).
    
    Worked examples:
    - Slice 04: gdsconfigformcustomslave is empty in the dev DB
      (0 rows). Updated the open verification item to confirm this
      rather than leave the framing "depends on the deployment".
    - Slice 05: side-by-side diff of 重庆展印's Sp_SalSalesCheck vs
      the standard. Quantified differences (1714 vs 723 lines, same
      14-param signature, override adds CbxSrcNoCheck branch and
      strips temp-table aggregation, 12 sibling procs use the same
      CbxSrcNoCheck pattern). Added a copy-pasteable diff command.
    
    Honest scope acknowledgement:
    - api-reference/internal.md: explicit "what this catalog
      includes vs treats as illustrative" paragraph. ~19 framework-
      primitive controllers documented; ~52 business-domain
      controllers (workorder/salesorder/productionPlan/etc.) treated
      as illustrations of the framework at work, with grep guidance
      for maintainers who need to find them.
    
    Auto-catalog regenerated:
    - Ran scripts/gen_catalog.py against live DB. No changes
      (catalog was already current); 3081 generated pages.
    
    Pass E save trace:
    - Tried multiple angles (UI flow, hand-crafted POST with token
      in Authorization header, fetch interception). Edit-mode UI
      didn't yield a save fire under our setup (Ant Design grid +
      Vue SPA edit-mode peculiarity). Read trace remains
      fully verified end-to-end. Save body shape is documented in
      the Javadoc on BusinessBaseController.java:161-163 and
      reflected in the wiki; live save corroboration deferred again.
    zichun authored
     
    Browse Code »
  • Second commit completing the verification plan after the first commit
    covered Pass A + most of Pass B P0/P1 + Pass C1/C2.
    
    P1 gaps:
    - slices/02-multi-tenancy.md: add the four-table sTableNameList
      exception (gdsformconst, gdsmodule, gdsconfigformmaster,
      gdsconfigformslave strip tenant cols at write); rewrite query-shape
      section to distinguish global framework metadata from tenant-scoped
      overlays + business state; flag dev DB has only 8S_001 in
      sisversionflow despite gdsmodule.sVersionFlowCode referencing
      EBC-SD/EBC-RD/EBC-MDM/etc.; add live row counts (1002 untagged,
      322 8S_001, 15 EBC-SD-002, …).
    - api-reference/internal.md, messaging.md, notifications.md verified
      as-is (Pass A surface fixes were sufficient, all file paths exist).
    
    P2:
    - slices/04-custom-field.md: close out the merge-code open item —
      merge is Java at BusinessBaseServiceImpl.java:246-248
      (getFormSlaveData + getFormCustomSlaveData); the two views supply
      the master⋈slave shape, the merge itself is in Java.
    - slices/06-hardware.md: PlcScheduledTasks uses Spring @Scheduled cron
      (every 30s + every 1s), not Quartz directly.
    - concepts/thesis.md: fix the "four-table read" framing — actual reads
      are from gdsconfigformmaster (with overlays), gdsformconst,
      sysjurisdiction, sysbillnosettings, sysreport. Soften slice-1
      reference to remove the "four-table" misframing.
    - slices/03-report.md, concepts/api-surface.md, customization-channels,
      customization-layers, semantic-fk verified clean (script/客户/
      customer dirs = 18, 0 FK / 0 triggers on xly tables, both overlay
      views exist).
    
    P3:
    - reference/builder/define-form.md: rewrite cache-invalidation section
      to match the corrected architecture (synchronous @CacheEvict, not the
      JMS path).
    - builder/define-vtable, builder/permissions, builder/index,
      builder/attach-workflow, slices/07-workflow, glossary/index,
      reference/maintainer/index, slices/index, contributing/index
      verified appropriately marked deferred / consistent.
    
    Pass D consistency sweep:
    - Ports (8080/8090/8000/8091/8597/8598) consistent across pages.
    - Schema names consistently use xlyweberp_saas_ai;
      running-locally.md correctly documents the xlyweberp_saas vs _ai
      divergence.
    - Counts (1358 gdsmodule rows, 311 views, 1687 procs, 177 functions)
      consistent.
    - Module/Modle/Models codebase quirk consistently surfaced.
    - xlyPlc plugin framing consistent across index.md, tech-stack.md,
      slice 06.
    - vtable / virtual table — single canonical form ("virtual table") used
      in narrative; URL-style filename `define-vtable` preserved.
    - proc / procedure / stored procedure usage clean (long form for
      emphasis, short for lists).
    
    Pass E live traces (partial):
    - Slice 1 read flow CORROBORATED end-to-end at BACK admin/123 edition
      基础版/8s. Both documented URLs captured exactly:
        GET  /xlyEntry/business/getModelBysId/13?sModelsId=13                                      → 200
        POST /xlyEntry/business/getBusinessDataByFormcustomId/19211681019715574676360040?sModelsId=13 → 200
      including the redundant ?sModelsId=13 alongside the path variable.
      Updated slice-01 open verification items to mark the read item closed.
    - Slice 1 save flow + slices 2-6 traces deferred (would mutate shared
      dev DB; FROUNT enumeration declined; monthly usage limit reached).
    
    Pass C3 frontend inventory (partial):
    - BACK admin sidebar = 10 framework-builder modules: 系统模块配置,
      数据表内容配置, 界面显示内容配置, 接口自定义配置, 系统常量配置,
      系统权限配置, 常用操作配置, 用户信息配置, Mysql脚本配置, 图表配置.
    - 8/10 covered by existing wiki pages; 2 silent (常用操作配置,
      图表配置 — admin BACK utilities, not framework runtime).
    - FROUNT enumeration declined by user.
    zichun authored
     
    Browse Code »

  • Verified every factual claim in the hand-written prose against the
    codebase under ../xly/ and the live xlyweberp_saas_ai schema, and fixed
    the drift:
    
    - semantic-fk: clarified — zero FKs on xly tables; the ones that exist
      are all on bundled Activiti / Quartz schemas, which the runtime
      doesn't join through.
    - multi-tenancy / runtime / slice 2: corrected RequestAddParamUtil shape
      (16 keys, 56 lines), noted the parallel xlyApi copy.
    - slice 1: corrected line ranges for addUpdateDelBusinessData;
      clarified that sTableNameList is a cache-invalidation gate, not an
      authorisation gate; corrected the gdsroute claim — unregistered paths
      are NOT 404'd server-side, the SPA uses gdsroute as a client-side
      whitelist (web-verified).
    - runtime: fixed controller package paths
      (Gdsmodule/Gdsconfigform/Gdsconfigtb live in systemweb/, not
      businessweb/); added CheckFlowController.
    - sql-templates / proc-dispatch: 8 scaffolds, not 7 (sSqlStr.sql).
    - master-slave: removed table names that don't exist (accOrderCostAnalysisMaster,
      quoQuotationCalc, mftWorkOrderCalc, mftWorkOrderSlaveMoney);
      added the *_tmp family that does.
    - permissions: full rewrite. The original page described
      gdsjurisdiction as a per-(module, role, button) rule table backed by
      empty plat_base_authority_* lookups; reality is gdsjurisdiction is a
      per-module catalog of buttons/actions, with sysjurisdiction carrying
      the actual role/user grants.
    - Removed environment-specific facts (row counts, sizes, timestamps,
      per-DB enumerations) so the wiki documents the framework, not one
      particular DB snapshot.
    
    Auto-catalog generator (en/scripts/gen_catalog.py):
    - Rewritten to query MySQL directly via ~/.my.cnf (replaces the
      recon/*.tsv pipeline).
    - Stripped ephemeral fields from output (Rows, Data size, Created,
      Updated on tables; Created, Last altered on routines; Definer on
      views).
    - Strips the schema-name prefix from VIEW_DEFINITION so view bodies
      are portable across deployments.
    - Wipes and rewrites docs/auto-catalog/{tables,views,procedures,functions}/
      on each run.
    - Auto-catalog regenerated.
    
    New API Reference chapter (5):
    - concepts/api-surface.md introduces the three-tier design (xlyEntry
      internal, xlyApi external, xlyInterface webhooks).
    - api-reference/{index,internal,external,webhooks,messaging}.md cover
      each surface, with the data-driven /api/invoke{sApiCode} pattern,
      sysapi schema, token flow, and the SpringFox Swagger UI location on
      xlyInterface.
    - mkdocs nav: chapters renumbered (Auto-Catalog → 6, Glossary → 7,
      Contributing → 8); glossary/contributing wrapped as section indexes
      to render correctly under navigation.sections.
    
    Other:
    - Bilingual top-level README (Chinese + English).
    - requirements.txt: pymysql added for the new generator.
    zichun authored
     
    Browse Code »
  • Documents the xly (小羚羊) printing-industry ERP framework. Built with
    MkDocs Material; CJK search via jieba; 3,076 auto-generated catalog
    pages from recon/*.tsv plus hand-written prose for the framework's
    core mental model and end-to-end vertical slices.
    
    Phase 0 recon: stack, schema shape, framework metadata layer, scope.
    Phase 1 wiki: scaffold + auto-catalog + Slices 1-6 (Slice 7 deferred).
    
    Slice coverage:
      1. CRUD module (Hello World) — observed network + cited source
      2. Multi-tenancy & product editions — sBrandsId/sSubsidiaryId/sVersionFlowId
      3. View-backed module (read-only report)
      4. Custom field overlay (gdsconfigformcustomslave)
      5. Per-customer SQL override (script/客户/<customer>/)
      6. Hardware integration (xlyPlc, optional)
      7. Workflow (deferred — Activiti tables empty in dev DB)
    
    Concepts: thesis, modules-forms-vtables, master/slave, semantic-FK,
    customization channels & layers, multi-tenancy, request lifecycle.
    
    Reference (Builder): define-form, define-vtable, permissions,
    attach-workflow (deferred).
    
    Reference (Maintainer): runtime, proc-dispatch, cache-invalidation,
    sql-templates, deployment, activiti.
    reporkey authored
     
    Browse Code »