• 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 »

  • 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 »
  • Audit every concrete claim in the 41 hand-written en pages against the
    three primary sources (DB, source on cleanup branch, source-tree
    inventory). Fix divergent claims in place; preserve framing where
    verified.
    
    Substantive corrections:
    
    - request-lifecycle / runtime / slice 01: the metadata read sources from
      five tables/families (gdsconfigformmaster + overlays, gdsformconst,
      sysjurisdiction, sysbillnosettings, sysreport), not four. The map key
      `gdsjurisdiction` is misleading — the per-user grant read queries
      `sysjurisdiction`; `gdsjurisdiction` is the builder-side action
      catalogue. `gdsformconst`, `gdsconfigformmaster`, `gdsconfigformslave`
      are NOT tenant-scoped; they filter by form-id only.
    - multi-tenancy: four metadata tables (gdsformconst, gdsmodule,
      gdsconfigformmaster, gdsconfigformslave) are an explicit exception to
      the "every table tenant-scoped" promise — `sTableNameList` strips
      sBrandsId/sSubsidiaryId from writes against them.
    - sSaveProName / sSaveProNameBefore are pre/post-save HOOKS on top of
      the always-running base path (BusinessBaseServiceImpl.add/update),
      not either/or branches. Default add/update path is in
      BusinessBaseServiceImpl, not AddDelUpdCommonServiceImpl.
    - cache-invalidation: redis cache is cleared synchronously in BACK via
      @CacheEvict on CleanRedisServiceImpl during save. The JMS
      CHANGE_GDS_MODULE queue triggers PRO_ERPMERGEBASEGDSMODULE (base-data
      merge), NOT cache invalidation despite the name. Cross-node
      coherence open question (no custom CacheManager bean configured).
    - messaging: enumerate all 24 P2pQueue destinations grouped by intent;
      fix CHANGE_GDS_MODULE description; clarify single Consumer.java with
      24 @JmsListener methods (not 24 listener classes).
    - API paths: /checkflow lowercase (mapping value, not class name);
      /procedureCall/doGenericProcedureCall (not /business/genericProcedureCall*).
    - tech-stack: Druid 6 java imports + 16 yml mentions (was 25 conflated);
      fastjson per-module xlyInterface 9 (was 10); commons-lang3 39 (was 41);
      @Document classes 20 PLAT_* + 2 DIKE_TEST* (was "all PLAT_*"); xlyPersist
      activiti hit is IdGen.java (was BaseDao.java); add Springfox to
      declared-but-no-imports table; reconcile module list to 11 framework
      core + xlyPlc plugin + xlyPlatConstant utility.
    - index.md: clarify xlyFace as "in build, not documented"; add xlyErpTask
      / xlyPlatTask scheduler bullet; correct MongoDB framing (caller is in
      xlyPersist with no consumers, not xlyPlat*); add xlyPlc note; extend
      backup-table OOS to cover *_copy1 / *_history / *YYYYMMDD[HHMMSS].
    - deployment.md: split deployable Boot apps from library modules;
      enumerate 12 commented-out includes (was 3); remove xlyPlatConstant from
      out-of-scope Plat* list; split profile permutations by service.
    - activiti.md: add xlyApi to 5.17 dependency list; replace speculative
      BPMN path hint with verified state; name actual ActivitiConfig.java;
      note act_id_* are views projecting xly users into Activiti shapes.
    - api-reference/external.md: fix bearer-token validation flow (sysapibrand
      via AES-decrypted corpid, not sysapithirdtoken); /online/* are page
      renders not API execution; /pro/* mostly returns Thymeleaf views; mark
      sysapidbtodb as xlyFlow-owned; /token/getToken accepts GET and POST.
    - api-reference/webhooks.md: add Swagger Docket caveat (UI shell ships but
      no Docket bean → /v2/api-docs effectively empty); flag /send/sendQw as
      stub (returns "ok").
    - slices/03-report.md: fix dir path xlyEntry/com/xly/report/ →
      xlyEntry/com/xly/web/report/; reframe PrintReportControllerOld as dead
      source (file body fully commented out).
    - concepts/modules-forms-vtables.md: add 22-prefix glossary table
      (gds/sys/sis/sft/ele/mft/sal/quo/acc/pur/ops/cah/sgd/ept/mit/pit/qly/
      kpi/udf/viw_/plat_/ai_/act_/qrtz_) so a maintainer can enumerate
      business-data domains at a glance.
    - concepts/master-slave.md: disambiguate document-row pattern from
      DataSource master/slave (different concept, name overlap).
    - proc-dispatch.md: add proc-name molds (Sp_*_BeforeSave/AfterSave/
      SaveReturn, sp_btn_*, PRO_ERPMERGE*) + function-layer paragraph
      (Fun_*/Fn_*/get_*; SQL-called, not Java-dispatched).
    - concepts/index.md: schema label MySQL\nxlyweberp → xlyweberp_*.
    
    Pass E (live behavioural traces) deferred — source/DB-side audit was
    thorough; live traces best done as a follow-up sweep against a running
    instance.
    zichun authored
     
    Browse Code »

  • 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 »