Web application engineering

Engineering this portfolio

A working Next.js and Payload website, with an editable content model and explicit rules for what visitors can read.

Active

Objective and scope

This site needs to do two jobs: publish a useful professional record and let me maintain it through a CMS. Draft pages, deleted records, private documents, and unfinished qualifications must not appear as public evidence. The repository is private, so the case study includes selected implementation excerpts visitors can read here.

Contribution and decisions

My role is to set the content requirements, review the career claims, and maintain the portfolio. This iteration includes AI-assisted implementation and review. The design keeps public reading, authenticated editing, and credential-document release as separate decisions. Server-rendered pages read through the CMS access rules instead of exposing the content collections directly to anonymous API clients.

Implementation evidence

Public reading

  1. Visitor
  2. Next.js public routes
  3. published Payload records
  4. PostgreSQL

Content editing

  1. Authenticated administrator
  2. Payload CMS
  3. drafts / published records

Media

  1. Published pages
  2. media references
  3. Vercel Blob
Application architecture: public pages read published CMS records, authenticated administrators edit content, and page media is stored in Vercel Blob. This is a source-derived application diagram, not a network map or security-test result.

cms/access.ts · collection read policy

const publishedAndNotDeleted: Where = {
  and: [
    { _status: { equals: "published" } },
    { deletedAt: { exists: false } },
  ],
};

export const publishedOrAuthenticated: Access = ({ req }) => {
  if (req.user) return true;
  if (req.payloadAPI && req.payloadAPI !== "local") return false;

  return publishedAndNotDeleted;
};
Selected source from cms/access.ts. Authenticated reads, anonymous remote API requests, and anonymous local reads take different branches. Types and unrelated access functions are omitted; this excerpt is not a complete authorization model.

Environment and structure

Public pages use the Next.js App Router and server-side Payload queries. PostgreSQL stores the records; Payload provides the authenticated editing interface. Media is stored in Vercel Blob. The diagram shows these application relationships, not a deployed network topology. A media reference is separate from permission to publish a credential download.

Defensive controls

The excerpt has three branches: an authenticated request may read the collection; an anonymous remote API request is denied; an anonymous local query receives a condition requiring both published status and no deletion timestamp. Public page queries also use a publication condition. Draft preview is a separate authenticated path. Credential downloads have their own publication checks; this one function does not enforce every boundary in the application.

Lessons learned

An accurate page is only part of the job. The CMS state, access rules, linked documents, and deployment checks also need to agree. A status label in the interface cannot substitute for a rule at the data boundary.

Validation record

14 October 2026 (UTC) — revision 5391484b83c849d0e9be3d6c75e15b9487655058: the complete verification run recorded 609 passing unit tests and 4 skipped tests across 57 files. Its full browser run recorded 56 passes and one failure caused by a stale roadmap-title expectation.

14 October 2026 (UTC) — revision 055b99af1e7300fda0a54bfdf7a7937293c83f29: after correcting that metadata expectation, GitHub Actions run 38499116464 passed the required targeted lanes, including 5 public browser tests. This was a targeted rerun, not a second complete browser suite.

These are historical checks of those revisions. CI logs are in the private repository; these results are a published summary, not a public reproduction package or an independent assessment of the live service.

Implementation and findings

The site supports CMS editing, project and credential detail pages, authenticated previews, and public document links that depend on explicit release fields. The publication condition and request branching shown here are implemented source, not a proposed control. The access-policy unit tests exercise returned conditions with synthetic request objects; browser tests cover separate application workflows.

Limits and next steps

The full repository is private. Visitors can inspect the running site, the architecture diagram, and the selected source excerpts here. The historical checks do not establish that every deployed path is defect-free. This is personal application work, not professional penetration testing, incident response, or a completed security lab. Further work includes clearer public examples of credential-release behavior and keeping this record aligned with subsequent releases.

Authorized scope

The Security page describes the live service’s testing policy. This case study does not expand that authorization.

Tools and technologies

Next.js · TypeScript · Payload CMS · PostgreSQL · Vitest · Playwright