Hacker DirectoryHacker Directory

WEB / WEB-16.04

Service layer, business logic, and templates

A public note domain result and its HTTP response are different decisions. Follow ownership across controller, service, repository, and template.

CORE · RED · BLUE · ARTIFACT · PRACTICE

1. Core · Mechanism

Read every scenario without motion

Published note

  1. Choose public note

    The client prepared GET /service/tea for the public catalog. Choosing the key is only read intent; the controller, service, repository and renderer have not received this request.

    Duru / Client
    GET /service/tea ready
    HTTP controller
    No request
    Service / domain
    Not called
    Repository
    No read
    Template renderer
    Not called
  2. Request arrived

    The controller received the public GET request; this arrival has not yet produced a service/domain result.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/tea received
    Service / domain
    Not called
    Repository
    No read
    Template renderer
    Not called
  3. Use-case call

    The controller passes the key to the service; this same-process function call is not drawn as a network packet.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/tea received
    Service / domain
    Query tea
    Repository
    No read
    Template renderer
    Not called
  4. Read record

    The repository reads the harmless fixture record; finding data alone does not establish its availability decision.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/tea received
    Service / domain
    Query tea
    Repository
    Found; published=true
    Template renderer
    Not called
  5. Rule result

    The tea record exists and satisfies published=true. The service prepares available with a title-only view model, title=Tea & Bread. The whole internal repository record and any new write are outside this presentation decision.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/tea received
    Service / domain
    Available; title=Tea & Bread
    Repository
    Found; published=true
    Template renderer
    Not called
  6. Render text

    The fixed h1 HTML text slot transforms title=Tea & Bread into body <h1>Tea &amp; Bread</h1>. The raw title stays unchanged; the ampersand is represented for this context. The body is ready but the client has not received it.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/tea received
    Service / domain
    Available; title=Tea & Bread
    Repository
    Found; published=true
    Template renderer
    <h1>Tea &amp; Bread</h1> ready
  7. HTTP mapping

    The controller maps the domain result to the selected HTTP policy; this read-only action is not a database commit.

    Duru / Client
    Waiting response
    HTTP controller
    200 HTML ready
    Service / domain
    Available; title=Tea & Bread
    Repository
    Found; published=true
    Template renderer
    <h1>Tea &amp; Bread</h1> ready
  8. Response arrived

    The client now received the 200 response and <h1>Tea &amp; Bread</h1> body. This arrival differs from the earlier service/renderer result. Browser parsing, DOM/pixels and database commit are not shown by this step.

    Duru / Client
    200 HTML received
    HTTP controller
    200 HTML ready
    Service / domain
    Available; title=Tea & Bread
    Repository
    Found; published=true
    Template renderer
    <h1>Tea &amp; Bread</h1> ready

Draft note

  1. Choose public note

    The client prepared GET /service/draft for the public catalog. Choosing the key is only read intent; the controller, service, repository and renderer have not received this request.

    Duru / Client
    GET /service/draft ready
    HTTP controller
    No request
    Service / domain
    Not called
    Repository
    No read
    Template renderer
    Not called
  2. Request arrived

    The controller received the public GET request; this arrival has not yet produced a service/domain result.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/draft received
    Service / domain
    Not called
    Repository
    No read
    Template renderer
    Not called
  3. Use-case call

    The controller passes the key to the service; this same-process function call is not drawn as a network packet.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/draft received
    Service / domain
    Query draft
    Repository
    No read
    Template renderer
    Not called
  4. Read record

    The repository reads the harmless fixture record; finding data alone does not establish its availability decision.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/draft received
    Service / domain
    Query draft
    Repository
    Found; published=false
    Template renderer
    Not called
  5. Rule result

    The draft record exists but published=false fails public availability. The service returns unavailable; no title view model or renderer call is produced.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/draft received
    Service / domain
    Unavailable
    Repository
    Found; published=false
    Template renderer
    Not called
  6. HTTP mapping

    The controller maps unavailable to 404 and the Not available body under this public-read contract. Draft and absent receive the same external response; the renderer is not called and no persistence write/commit occurs.

    Duru / Client
    Waiting response
    HTTP controller
    404 Not available ready
    Service / domain
    Unavailable
    Repository
    Found; published=false
    Template renderer
    Not called
  7. Response arrived

    The client received 404 Not available. This external result alone cannot distinguish an existing unpublished draft from a missing absent key; the internal cause requires repository/domain evidence.

    Duru / Client
    404 Not available received
    HTTP controller
    404 Not available ready
    Service / domain
    Unavailable
    Repository
    Found; published=false
    Template renderer
    Not called

Missing note

  1. Choose public note

    The client prepared GET /service/absent for the public catalog. Choosing the key is only read intent; the controller, service, repository and renderer have not received this request.

    Duru / Client
    GET /service/absent ready
    HTTP controller
    No request
    Service / domain
    Not called
    Repository
    No read
    Template renderer
    Not called
  2. Request arrived

    The controller received the public GET request; this arrival has not yet produced a service/domain result.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/absent received
    Service / domain
    Not called
    Repository
    No read
    Template renderer
    Not called
  3. Use-case call

    The controller passes the key to the service; this same-process function call is not drawn as a network packet.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/absent received
    Service / domain
    Query absent
    Repository
    No read
    Template renderer
    Not called
  4. Read record

    The repository reads the harmless fixture record; finding data alone does not establish its availability decision.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/absent received
    Service / domain
    Query absent
    Repository
    No record
    Template renderer
    Not called
  5. Rule result

    The repository found no record for key absent. The service returns unavailable without assigning a published value to a nonexistent record. No title view model or renderer call is produced.

    Duru / Client
    Waiting response
    HTTP controller
    GET /service/absent received
    Service / domain
    Unavailable
    Repository
    No record
    Template renderer
    Not called
  6. HTTP mapping

    The controller maps unavailable to 404 and the Not available body under this public-read contract. Draft and absent receive the same external response; the renderer is not called and no persistence write/commit occurs.

    Duru / Client
    Waiting response
    HTTP controller
    404 Not available ready
    Service / domain
    Unavailable
    Repository
    No record
    Template renderer
    Not called
  7. Response arrived

    The client received 404 Not available. This external result alone cannot distinguish an existing unpublished draft from a missing absent key; the internal cause requires repository/domain evidence.

    Duru / Client
    404 Not available received
    HTTP controller
    404 Not available ready
    Service / domain
    Unavailable
    Repository
    No record
    Template renderer
    Not called

ACTORS · STATE · DATA FLOW

The controller carries results; the domain selects them

A service layer organizes a use-case flow: invokes suitable data access, applies a domain rule, and returns a result the controller can consume. This public-note rule permits presentation when published=true. The controller maps a path to a note key, the repository reads the record, and the domain determines availability. Service does not mean a remote HTTP microservice or separate process here; these are function calls inside the selected process.

Business logic defines what the application considers valid; choosing HTML tags or writing headers is a different responsibility. In a DDD design, the application layer orchestrates while the domain owns business rules. Smaller applications can use a different structure. Ask who makes the published decision across HTML and JSON presentations, rather than relying on class names.

The Atlas repository defines tea as published=true and draft as published=false; absent finds no record. The first becomes a view model; the other two map to the same 404 Not available response. That status does not disclose which record exists. This is a public-catalog availability rule, not an identity or object-authorization policy. Successful data access also differs from permission to present a record.

Templates place data in an interpreter context

A template is a trusted output structure selected by the application; its view model is data. Placing Tea & Bread in the HTML text slot produces <h1>Tea &amp; Bread</h1>. A JSON representation can retain Tea & Bread as its string value. Encoding decisions cannot be copied blindly between contexts: HTML text, attributes, URLs, JavaScript, and CSS have different interpretation rules.

The ampersand transformation for this fixed harmless title does not prove an entire engine secure. Production work must understand engine auto-escaping and permitted output contexts. Keeping template source separate from variable values supports a design in which displayed strings are not reinterpreted as programs. This lesson uses one fixed HTML text slot, with no dynamic template code or executable context.

Express res.render documents combining a template with values. Its view engine cache holds the underlying template rather than one ready-made body for every request. Our small renderer also yields different bodies for Tea & Bread and Coffee in the same fixed structure. It is not an Express/Pug execution. A completed service result or response.end call is not a database transaction commit; this read-only example has no persistence operation.

2. Red · Trust & Impact

Read every scenario without motion

Draft rule

  1. The public-catalog rule was selected

    The rule requires record exists AND published=true. A repository finding a record alone is not availability for this public presentation.

    Catalog input/record
    Key=draft
    Service/render rule
    Service rule not applied
    Presentation boundary
    Renderer not called
  2. The repository result was read in scope

    The draft row has repositoryFound=true. This store result is not broadened into identity acceptance, publishing permission or client-delivery approval.

    Catalog input/record
    Repository found=true
    Service/render rule
    Published state not read
    Presentation boundary
    Renderer not called
  3. The published gate was preserved

    published=false gives serviceOutcome=unavailable. An HTML or JSON adapter exposing the repository record outside this rule would not preserve the same contract.

    Catalog input/record
    Record exists; unpublished
    Service/render rule
    Service unavailable
    Presentation boundary
    Renderer not called
  4. Renderer dispatch was withheld

    rendererInvoked=false remains. A title view model is not treated as prepared for the existing draft; service outcome constrains presentation input.

    Catalog input/record
    Record exists; unpublished
    Service/render rule
    Availability gate denied
    Presentation boundary
    No renderer dispatch
  5. HTTP mapping was separated from the domain outcome

    Status 404 with body Not available is this product’s unavailable mapping. It does not prove repository absence; the absent row receives the same response.

    Catalog input/record
    Known: draft exists
    Service/render rule
    Known: unavailable
    Presentation boundary
    Declared 404 Not available
  6. Presentation authority stayed with its owner

    This public rule is not identity policy. Preserving the draft response does not validate all private-access controls; this example has no writes or credentials.

    Catalog input/record
    Public availability rule
    Service/render rule
    No publish bypass assumed
    Presentation boundary
    No broader authorization claim

HTML text

  1. The fixed template slot was selected

    Normal title Tea & Bread is harmless data. The fixed h1 text slot and data input remain separate responsibilities.

    Catalog input/record
    Title: Tea & Bread
    Service/render rule
    HTML text slot
    Presentation boundary
    Output not prepared
  2. The view model was taken after the rule

    The available normal row carries a title-only view model. The repository’s entire internal record is not automatically supplied as editable template context.

    Catalog input/record
    View model: title only
    Service/render rule
    Fixed HTML text slot
    Presentation boundary
    Output not prepared
  3. Text-context encoding was applied

    The HTML body is <h1>Tea &amp; Bread</h1>. Ampersand data is represented in HTML text context; the transformation creates no new template source.

    Catalog input/record
    Raw title unchanged
    Service/render rule
    Text encoder selected
    Presentation boundary
    Encoded h1 body
  4. The encoder was not carried into another context

    This HTML text encoder is not a universal control for URL or script contexts. A new context requires its own appropriate rule and sink policy.

    Catalog input/record
    Harmless title data
    Service/render rule
    HTML text scope only
    Presentation boundary
    No universal encoder claim
  5. A serialized body was not treated as receipt

    A prepared HTML body is not the moment of client receipt or browser parsing. Completion retains serviceResultIsClientArrival=false.

    Catalog input/record
    View model known
    Service/render rule
    HTML body prepared
    Presentation boundary
    Client arrival not proven
  6. The read-only output boundary was preserved

    persistenceOperation=null and commitProven=false. Correct text encoding proves neither record mutation nor the safety of every template-engine option.

    Catalog input/record
    Known: selected text transformation
    Service/render rule
    Fixed data/source boundary
    Presentation boundary
    No commit or universal rendering claim

ASSUMPTION · BOUNDARY · CONTROL

Ownership of one rule across different entry points

Start by identifying which service/domain result each controller consumes. If an HTML route gets published from the service while a JSON route directly serializes repository records, one availability contract is applied differently. The possible impact is a broken intended presentation boundary; a method or framework name cannot explain it. The control is a shared rule owner and evidence that both presentations depend on its result.

A 404 for draft does not prove an empty repository: the service can mark an existing record unavailable. absent deliberately has the same response. When outside evidence cannot distinguish those causes, report only the response contract. Controller, service-result, and repository observations together clarify the boundary. These are permitted benign catalog states, with no attack or authorization bypass.

Interpreting output and completion accurately

The encoded Tea & Bread HTML body demonstrates data transformation for the selected text slot. Reusing that transformation as a URL or script-context security control changes its meaning. The failure condition is a mismatch between context and encoder; possible effects include incorrect rendering or unexpected interpretation. Keep contexts fixed, use appropriate engine/library controls, and review the reasons for raw-output choices.

A ready view model, serialized body, and response received by a client are separate stages. None alone establishes persistence. Reviewing a write use case would require commit results, rollback boundaries, and response policy; there are no writes here. Different renderer outputs for two titles prove per-input transformation only, not cache isolation, browser parsing, or every template-engine option.

3. Blue · Secure development & defense

Read every scenario without motion

404 reasons

  1. Draft and absent observations were selected

    Both rows give status=404 and body Not available. Review separates equal public responses from internal availability causes.

    Service/renderer observation
    Draft + absent rows
    Cause/input review
    Cause fields not read
    Evidence conclusion
    External cause unknown
  2. The draft-cause field was read

    Draft has repositoryFound=true and published=false. Its service-unavailable outcome follows an existing record failing the public rule.

    Service/renderer observation
    Draft exists; unpublished
    Cause/input review
    Draft: unavailable
    Evidence conclusion
    Response: 404 Not available
  3. The absent-cause field was read

    Absent has repositoryFound=false. This is a second internal cause for the same serviceOutcome; the public body need not distinguish them externally.

    Service/renderer observation
    Absent record not found
    Cause/input review
    Absent: unavailable
    Evidence conclusion
    Response: 404 Not available
  4. Renderer withholding was compared

    Both rows have rendererInvoked=false. Gate outcome and renderer dispatch are compared independently of status.

    Service/renderer observation
    Two unavailable reasons
    Cause/input review
    No renderer in either row
    Evidence conclusion
    Public responses equal
  5. Cause was not assigned from external status alone

    A consumer observing only 404 cannot distinguish draft from absent under this contract. The internal ledger supplies the distinction; without it, cause remains UNKNOWN.

    Service/renderer observation
    Public 404 observation only
    Cause/input review
    Internal fields required
    Evidence conclusion
    UNKNOWN from status alone
  6. The availability conclusion stayed bounded

    The supplied ledger explains two benign causes. A 404 establishes neither attack attribution, private authorization nor storage failure.

    Service/renderer observation
    Known: declared unavailable reasons
    Cause/input review
    Known: renderer withheld
    Evidence conclusion
    Other causes require separate evidence

Render input

  1. Two renderer outcomes were selected

    Normal title Tea & Bread and secondRender title Coffee are different data. sameTemplate=true shows the same template receiving different inputs.

    Service/renderer observation
    Two title inputs
    Cause/input review
    Output not read
    Evidence conclusion
    No browser evidence
  2. Normal HTML output was read

    The normal body is <h1>Tea &amp; Bread</h1>. It describes fixed text-slot encoding, not an actual browser DOM.

    Service/renderer observation
    Tea & Bread input
    Cause/input review
    Encoded Tea &amp; Bread output
    Evidence conclusion
    No browser evidence
  3. The second output was compared

    Coffee input produces <h1>Coffee</h1> with sameOutput=false. A template cache does not mean that all rendered bodies are identical.

    Service/renderer observation
    Coffee input
    Cause/input review
    Same template; different output
    Evidence conclusion
    No browser evidence
  4. Transformation evidence stayed in context

    The bodies show only per-input transformation. Cache isolation, engine auto-escaping options and script/URL contexts lie outside their scope.

    Service/renderer observation
    Two fixed public inputs
    Cause/input review
    Selected HTML text context
    Evidence conclusion
    No universal engine claim
  5. Client-knowledge evidence was separated

    Prepared strings do not establish browser parsing, DOM layout or rendered pixels. Client-receipt and render observations require their own sources.

    Service/renderer observation
    Prepared body strings
    Cause/input review
    Known: transformation outputs
    Evidence conclusion
    UNKNOWN: client rendering
  6. The renderer conclusion was not broadened

    sameTemplate=true and sameOutput=false are consistent here. No conclusion is made about database commits or actual framework-cache behavior.

    Service/renderer observation
    Known: same template
    Cause/input review
    Known: different title outputs
    Evidence conclusion
    UNKNOWN: broader engine/runtime behavior

IMPLEMENTATION · SECURITY CONTROL · VERIFICATION

Record boundaries separately in the decision ledger

The ledger records repositoryFound=true, published=true, serviceOutcome=available, and rendererInvoked=true for tea. draft exists but becomes unavailable with no renderer invocation; absent has no record. These are selected teaching observations, not a product log schema. Reading outcome-to-status mapping independently separates HTTP policy from a business rule.

Control equivalence requires more than matching status codes. Check that unavailable never reaches rendering, that available supplies only the title view model, and that JSON/HTML adapters consume the same result. A read-only repository call demonstrates record access; a prepared response proves neither client arrival nor database commit. The artifact explicitly separates and denies those latter claims.

Limits of the selector and context check

XPath count(/audit/decision[@outcome="unavailable" and @rendered="true"]) counts authored observations that reach rendering despite an unavailable decision. Normal data gives 0; a deliberately inconsistent positive fixture gives 1. A normal draft 404 is benign and expected. An absent event can also produce 0, meaning insufficient evidence rather than proven rule enforcement. The selector evaluates this observation contract only.

Review encoding with rawTitle and htmlBody together: Tea & Bread becomes Tea &amp; Bread in HTML text. No other context is used, so the evidence stays narrow. Express view caching is a documented behavior; the small renderer demonstrates different inputs producing different bodies through one function. Actual engine auto-escaping, middleware, browser DOM, transactions, and production caching require their own evaluation.

Keep the business decision independent of adapters

Finding a repository record is not permission to publish it. The service explicitly evaluates published and unavailable; JSON and HTML adapters must not bypass that shared decision. The renderer receives only the required title view model rather than automatically exposing every repository field. Use the appropriate encoder or verified engine auto-escaping for HTML text; JSON serialization is a different control.

Verify that both adapters consume available for tea and that draft never invokes rendering. Tea & Bread becomes Tea &amp; Bread in HTML text without changing the original title. Moving the value to an attribute or another context requires reconsidering the encoder. If the service decision or renderer invocation is not observed, a 404 or plausible body alone cannot establish enforcement.

NOW APPLY IT TO THE CASE

Which result is carried by business rules and text transformation?

The public-catalog rule treats drafts and absent records as unavailable. When an available title is transformed into a fixed text slot, rendered strings and client receipt remain separate.

Reconstruct decision order for input, server processing and response in the case. Parsed or valid data is not a completed operation; identify each owner and its condition.

Open the related case file ↗

READ THE EXAMPLE TOGETHER

Public-note decision and render ledger

Select a field and examine what it supports and where the evidence ends.

Read the raw artifact and field explanations
{
  "rule": {
    "name": "public catalog availability",
    "predicate": "record exists AND published=true",
    "scope": "public read-only synthetic notes, no identity policy"
  },
  "normal": {
    "key": "tea",
    "repositoryFound": true,
    "published": true,
    "serviceOutcome": "available",
    "rendererInvoked": true,
    "viewModel": {
      "title": "Tea & Bread"
    },
    "htmlBody": "<h1>Tea &amp; Bread</h1>",
    "status": 200
  },
  "draft": {
    "key": "draft",
    "repositoryFound": true,
    "published": false,
    "serviceOutcome": "unavailable",
    "rendererInvoked": false,
    "status": 404,
    "body": "Not available"
  },
  "absent": {
    "key": "absent",
    "repositoryFound": false,
    "serviceOutcome": "unavailable",
    "rendererInvoked": false,
    "status": 404,
    "body": "Not available"
  },
  "secondRender": {
    "title": "Coffee",
    "htmlBody": "<h1>Coffee</h1>",
    "sameTemplate": true,
    "sameOutput": false
  },
  "completion": {
    "persistenceOperation": null,
    "commitProven": false,
    "serviceResultIsClientArrival": false
  },
  "selector": {
    "language": "XPath",
    "xml": "<audit><decision outcome=\"unavailable\" rendered=\"false\"/></audit>",
    "xpath": "count(/audit/decision[@outcome=\"unavailable\" and @rendered=\"true\"])",
    "expected": 0,
    "positiveFixtureXml": "<audit><decision outcome=\"unavailable\" rendered=\"true\"/></audit>",
    "positiveExpected": 1,
    "scope": "Only authored protocol-decision observations, not product log field names or a live HTTP capture.",
    "missingFieldBehavior": "Missing observation is insufficient evidence; zero matches is not proof of correct runtime behavior."
  }
}
serviceOutcome
Domain decision between repository result and HTTP status.
htmlBody
Encoded output of one fixed HTML text context.
completion
Boundary that does not equate result, arrival, and commit.

Fixed benign notes, in-memory repository, and tiny renderer; not an Express/Pug, transaction, or browser DOM capture.

Two reality checks

A service layer is always a remote HTTP service.

Here controller, service, repository, and renderer share a process; distinct responsibilities do not require network hops.

A template cache gives every request the same ready-made HTML.

Express view caching retains the underlying template; output is re-rendered with data. Output caching is a separate decision.

YOUR TURN

Work through this story.

Predict the outcome, find the evidence boundary, and explain it in your own words.

The repository found a draft row but published=false. Does the public service call the renderer?

  1. No; unavailable/404 and rendererInvoked=false.
  2. Yes; a public template always runs when a data row is found.
Read the explained answer

No; unavailable/404 and rendererInvoked=false. — The rule requires record exists AND published; found alone is not public availability.

Why does Tea & Bread become Tea &amp; Bread in HTML source?

Selected lesson artifact fields; teaching example

normal.viewModel
{"title":"Tea & Bread"}
normal.htmlBody
<h1>Tea &amp; Bread</h1>
  1. The template transforms the title into another business record.
  2. Text-context encoding preserves the literal ampersand through representation.
Read the explained answer

Text-context encoding preserves the literal ampersand through representation. — ViewModel is text data; encoded HTML source uses different bytes while preserving the intended visible title.

The same template produces different output for Coffee. Explain service/repository/template and client-arrival roles.

Read the explained answer

The repository retrieves a record; the service establishes the published predicate and viewModel. A template generates context-appropriate HTML from the viewModel; different input yields different output. A service result is not client arrival; this read-only example has persistenceOperation null and commitProven=false.

□ I distinguished data-access/business-rule/presentation roles.

□ I did not count a template result as delivery/commit.

Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples

Sources and scope