- AI
- Process
- Next.js
How I built the new startify.space with AI — from Figma and Framer to Next.js on my own server
From auditing the old site, through splitting the work between Codex and Claude Code, testing and language versions, to staging, the domain and Google Analytics.
Author: Mateusz Madura
Independent Product Designer · LinkedIn (opens in a new tab)
22 min read
Contents (14)
When I showed the new version of my website, a comment appeared under my LinkedIn post (opens in a new tab): “Nice site! Would you be up for describing the process somewhere so others could learn something from it? ;)” That comment sums up the problem with most stories about AI coding: we show the result, but rarely the whole process.
The new startify.space did not come from typing a single prompt. Nor did it start from a blank page. I had a working website in Framer, a design in Figma, a library of materials, several years of projects to show and a very specific vision of how it should all look. What I lacked was an independent implementation that could keep growing, a proper repositoryThe place where Git stores the project files together with their full history of changes. A remote copy, e.g. on GitHub, protects the work and makes collaboration easier., tests, Polish and English versions, and a process in which AI not only writes code but also helps keep it in check.
Above all, I wanted the freedom to keep building the site. Figma and the live Framer site were the sources of the current solution, but I didn’t want every further change to require designing it in Figma first and then assembling it in Framer. I wanted to add articles, case studies and new features on my own, flexibly, directly in the repository.
I used two tools for the work: OpenAI Codex and Claude Code. I gave them different roles and kept all product decisions and the approval to publish for myself. That separation turned out to matter more than the choice of any particular model.
This text describes the entire process: from auditing the old website and measuring the design, through dividing the work between the agents, implementation, testing and language versions, to stagingA test copy of the website on a real server, hidden from visitors and search engines. It lets you check a release before it goes live on the real domain., server configuration, the domain and Google Analytics. It is also a guide you can adapt to your own project.
First, we agreed who was responsible for what
The biggest mistake would have been to treat two AI agentsAn AI tool that does more than answer questions: it carries out tasks on its own, reading project files, changing code and running commands. In this project, the agents were Codex and Claude Code. like two developers changing the same files at the same time. That is a fast track to conflicts, lost context and changes nobody can explain later.
So we split the responsibility into three roles:
| Role | Responsibility |
|---|---|
| Me — product owner | I set goals and priorities, assess the look and the content, resolve ambiguities and approve pushes, merges, deployments and domain changes. |
| Codex — coordinator | Analyses the state of the repository, breaks the work into tasks, guards the scope, documents the base commit, reviews handoffs, runs tests and reports risks. |
| Claude Code — lead developer | Implements clearly defined tasks on separate branches and hands over the result with a complete report. |
- Mateusz sets the goal
- Codex prepares the brief
- Claude implements
- Codex reviews
- Mateusz makes the decision
Every task went through the same cycle:
- Codex prepared a brief: the goal, the executor, the base commitA saved state of file changes in the Git history, with a description and an author. The base commit is a task’s starting point: the result is compared against it., the permitted files, what was excluded from the task, the acceptance criteria and the required tests.
- The executor checked the current state of the repository and confirmed it was starting from a clean treeA state in which the local copy of the project has no changes that are not saved in Git. Starting from a clean tree makes sure no accidental edits end up in the task..
- The work went onto a separate branchA separate line of changes in a Git repository. Each task was built on its own branch, so it did not mix with other work until it was accepted..
- The agent delivered only the agreed scope.
- After implementation, it ran the tests and carried out manual QA.
- The result ended with a local commit and a handoff report.
- Codex compared the result with the brief and the base.
- Only then did I decide: accept, revise or reject. PushSending local commits to a remote repository, such as GitHub. From then on, others can see the changes and automation can pick them up., mergeCombining the changes from one branch into another, usually into the main version of the project. In this process, a merge required the owner’s separate approval. and deployment always required separate approval.
This changes how you work with AI. Instead of a “build me a website” prompt, you have small, verifiable contracts.
A brief template you can copy
Goal: Executor: Branch: Base commit: Scope of work: Permitted files or areas: Out of scope: Acceptance criteria: Required automated tests: Required manual QA: Do not make any additional product decisions. If the sources contradict each other, describe the discrepancy and stop. Do not push, merge or deploy without separate approval.
Step 1. Before writing any code, we audited the sources
The starting point was not a single perfect design. The information was spread across:
- the live startify.space website in Framer,
- a Figma file with the desktop design,
- graphic materials and fonts,
- my notes and the decisions I made along the way,
- and, later on, the documentation and Git history.
We had to set a hierarchy. Figma was a very good source of geometry for the 1920 px view and of the original assets. The live website, on the other hand, was a better source of behaviour, responsiveness and interactions. When the design and the implementation differed, we did not guess. We described the difference and I made the decision.
At first, the audit covered five existing addresses: the homepage, the menu, Pssst, the case study and Shots. We broke down the eight sections of the homepage and made an inventory of images, SVGs, animations, fonts and analytics. We also checked the breakpointsA screen width at which the page layout changes, e.g. from one column to two. In this article, these include the 810, 1280 and 1920 px thresholds. generated by Framer.
Figma contained a complete design only for the 1920 px width. We had to recreate tablet and mobile based on the existing implementation. It is an important lesson: responsiveness does not follow automatically from a desktop screen in Figma.
In the end, we adopted four layout levels:
- mobile up to 809 px,
- tablet 810–1279 px,
- desktop 1280–1919 px,
- desktop XL from 1920 px.
The 1500 px threshold remained an additional breakpoint for the more complex layout and the navigation. We did not invent it “by eye” — it came from how the Framer website behaved.
The typography required a little investigation
Figma used the names Neue Montreal and PP Neue Montreal. These are not identical typefaces. We compared the metrics of the font files with what Framer was actually serving: glyph widths, cap height, x-height, weight and the number of characters.
The result was clear: the website used the 2018 release of Neue Montreal, not PP Neue Montreal. Had we chosen the typeface based only on a similar name, almost every line would have broken differently.
Next, we measured font sizes and line heights at several widths. We did not force everything to follow a single mathematical formula, because the original implementation was not perfectly systematic. First we recreated the actual state, and only later introduced deliberate deviations.
We measured the website, but we also had to measure the measurement
Framer kept some elements in their pre-animation state: with transparency and an offset, e.g. 24 px vertically. A standard position measurement in the browser takes the transform into account, so it returned a value different from the element’s real position in the layout.
Because of this, the first hero measurements were wrong. Instead of hiding the mistake, we recorded it in the documentation and changed the method. For the following sections, we disabled transforms, animations and transitions for the duration of the measurement, or subtracted the known offset.
This is one of the reasons AI needs documentation. An agent can measure a hundred elements very quickly, but if the method is wrong, you get bad data a hundred times faster.
Step 2. We built the technical foundation
We rewrote the website as a Next.jsA framework for building websites and applications with React. Among other things, it provides routing, server-side page generation and a build ready for publishing. application with React and TypeScript. Interactions were based on the Motion library, because a similar mechanism was responsible for movement on the original website. Styles used Tailwind as well as our own CSS stylesheets and tokens.
The final documented stack included:
- Next.js 16.3.5,
- React 19.3,
- TypeScript 6.0.3,
- Tailwind CSS 4.3.3,
- Motion 13.4,
- PlaywrightA tool for automatically testing websites in real browsers: it clicks, scrolls, types and checks the result the way a user would. for browser tests,
- axe for an automated audit of some accessibility rules.
We did not start with an abstract design system. First, we extracted the system that already existed in the design: colours, typography, grid modules, borders, spacing, buttons and breakpoints.
The result was a 16-column grid and three basic outer margins: 24 px on mobile, 40 px on tablet and 80 px on desktop. We separated content and projects from components. The case study data fed both the list on the homepage and the previous/next navigation in the case studies.
The project structure had a clear division:
app/ routes and layouts
components/ shared components, sections and case study blocks
dane/ content, projects, testimonials, shots and dictionaries
public/ images, SVGs, fonts and video
docs/ measurements, decisions and handoffs
tests/ unit and browser testsBase commit first, fast work second
After a few days of the first implementation, we discovered a serious risk: the whole project existed locally without a single commit and without a remote repository. There was no safe baseline for comparison, no information about who made which change and no simple way back to an earlier state.
We stopped development and created a base point. The code, documentation and materials, including video, went into a private GitHub repository, because the largest file fit within the limits of regular Git. Only from that moment could we safely work with separate branches, reviews and handoffs.
Next, we pinned the dependency versions, fixed lintingAutomatically checking code for errors and style inconsistencies without running the site. It is one of the first gates before the build. for the current version of Next.js and added CIContinuous integration: an automated process that runs checks such as linting, the build and tests on every change in the repository, and reports errors.. Installation was based on the lockfileA file that records the exact versions of every package the project uses. It makes the computer, the agent and the server install exactly the same set., so that the local machine, the agent and the CI server all received the same set of packages.
Step 3. We recreated the website section by section
We did not ask AI to write the whole website at once. Each section had a separate stage of measurement, implementation and comparison.
In the hero, we recreated the relationship between the text column, the portrait and the characteristic lines. The portrait had a transparent background, so it could not be converted to JPEG. It was also important to separate the image from its crop: it was the container that cropped the photo, not object-fit stretching the image itself.

In the following sections, we recreated the actual structure: column widths, the rhythm of the cards, the list of skills, testimonials, the project grid, the process, the about section, client logos and the footer. For each breakpoint, we checked not only the font size, but also changes in layout direction, the order of elements, the visibility of descriptions and how graphics were cropped.
Not every element was reproduced unchanged. For example, the hero got a minimum height of the screen, so that the portrait reached the bottom edge even with unusual window proportions. That was a product decision, not an agent’s accidental “fix”. Every departure from the old website was documented.
Case studies required a different approach
We built a shared block model for case studies: the opening, the goal, chapters, galleries, full-width graphics, the summary, credits and navigation to other projects. As a result, new case studies were not separate, hand-assembled pages, but data rendered by a shared template.
This is where we ran into one of Figma’s more interesting traps. Exporting a very tall frame was limited to 4096 px along the longer side. After that kind of scaling, one-pixel lines turned into lines more than 5 px thick. The problem occurred in both PNG and SVG.
The solution was to export to PDF, which preserved the vector geometry, followed by controlled rasterisation of the fragments we needed. Instead of trusting layer heights, we also analysed the actual boundaries of the visible sections, because some frames in Figma overlapped.
Assets were not copied blindly
Wherever possible, we took the originals from Figma and local materials, not the optimised copies downloaded from Framer’s CDNA network of servers around the world that deliver files, such as images, quickly. Framer served optimised copies of graphics through its CDN, which is why we preferred the originals.. The exceptions were elements that existed only in the implementation or whose behaviour had to be reconstructed from the DOMThe structure of a page that the browser builds from HTML and uses for display and scripts. We read the real sizes and behaviour of elements on the live website from the DOM..
Every image had its proportions, natural size and behaviour checked at several widths. For the videos in Shots, we prepared lightweight posters. The video files themselves started downloading only near the viewport, and only if the user had not limited animations. Thumbnails could be paused, and the video dialog had native controls.
As a result, a sample of the mobile Shots page with reduced motion enabled dropped from about 23 MB to about 1.2 MB and did not play videos automatically.
Step 4. We expanded the scope beyond a copy of the old website
Once the foundation was recreated, we started developing the website further. We added more case studies, a separate list of case studies, a knowledge base, refined interactions and full Polish and English versions.
The language versions live under /pl and /en. The neutral entry point chooses the language based on a saved choice or the browser’s preferences, but explicit language addresses never redirect users against their decision. The switcher leads to the equivalent of the same page and keeps the section anchor.
Interface copy went into separate dictionaries, and the case study data received Polish/English pairs. We also added:
- localised titles and descriptions,
- canonicalsA tag in the page code that tells search engines the page’s main, preferred address. It helps when the same content is available at several addresses.,
hreflangA tag that tells search engines a page has versions in other languages and where they are. It links the Polish and English equivalents of the same page. for PL, EN andx-default,- a sitemap,
- localised 404 pages,
noindexAn instruction telling search engines not to add a page to their results. Here it was used for the technical menu, error pages and staging, among others. for the technical menu and error pages,- a redirect map from the old Framer addresses,
- a 1200 × 630 Open Graph image for social media previews.
The old addresses led to their English equivalents, because that was the content the previous website presented. Before publishing, we checked the map of existing URLs instead of assuming that nobody linked to them anymore.
Step 5. Tests became part of the implementation
In AI coding, it is very easy to get carried away by how quickly changes are generated. The problem appears when every new prompt fixes one thing and breaks two others. That is why, over time, we built several layers of checks.
The basic gate included:
npm run lint
npm run typecheck
npm test
npm run buildOn top of that came Playwright tests in Chromium and WebKit. They checked navigation, the menu, language versions, redirects, the behaviour of forms and buttons, the Shots dialog, keyboard support, the reduced motion preference, the absence of horizontal scrolling and the state of images.
We created visual baselines for key views at boundary widths, including 390, 809, 810, 1279, 1280, 1499, 1500, 1700 and 1920 px. This meant we tested not only “phone, tablet, desktop”, but also the pixel before and after each breakpoint change.
Before publishing, we ran a separate audit covering the public routes in both language versions, images, JavaScript errors, HTTP statuses, metadata, horizontal scrolling and automated axe rules. The tests did not replace human judgement, but they turned many repetitive checks into a permanent gate.
The first audit found, among other things, insufficient contrast in some grey text, heavy videos and problems with autoplay controls. We fixed the colours, the way media loads and the behaviour with prefers-reduced-motion, and then ran the full set of checks again.
In one of the stages related to analytics, the build generated 30 pages, 15 unit tests passed, and 156 browser tests in Chromium and WebKit finished successfully. That does not mean a “perfect website” or full WCAGThe international Web Content Accessibility Guidelines. Among other things, they cover contrast, keyboard use and text for screen readers. compliance. It means we had repeatable proof for specifically described behaviours.
Step 6. Staging first, the domain later
The target hosting was cyber_Folks. The application was not a static export. We ran Next.js as a Node 22 application managed by Phusion PassengerSoftware on the hosting server that runs the Node.js application, looks after its process and passes browser traffic to it..
We started with an isolated staging environment on a technical domain. The application directory sat outside public_html, and access was protected with Basic AuthThe simplest password protection built into browsers: a login prompt appears before the page opens. Here it kept staging closed to accidental visitors.. Staging got an additional X-Robots-Tag: noindex, nofollow, noarchive header so that it would not end up in the index by accident.
We prepared two separate launchersA small start-up file that runs the application on the server and points to the version of the site it should serve. Separate launchers let staging and production be configured differently.:
- a staging one, which always added protection against indexing,
- a production one, without a global
noindex.
The launcher explicitly configured Passenger with the automatic HTTP server installation disabled and listened through the Passenger mechanism. It is a small detail, but without it the framework could have taken over the wrong server created in the process.
What a release to the server looked like
- We prepared a package containing only tracked sources and the launcher. No
.env,.git,node_modules, cache, logs or local configuration. - The package went into a new release directory, and before unpacking we checked the SHA-256 checksum and the list of files.
- We kept a copy of the current launcher,
.htaccessand application mapping, so that a rollbackGoing back to the previous working version after a failed release. Here it was enough to restore the previous launcher, without rebuilding the site. did not depend on rebuilding. - We installed dependencies on the server from the lockfile. We did not copy
node_modulesfrom macOS to Linux. - We ran the build on the hosting. In practice, building with WebpackTools that, during the build, bundle and optimise the site’s code into a version ready for publishing. Turbopack is the default in Next.js, but Webpack worked on the hosting. worked; the default Turbopack ran into the environment’s limitations.
- Only after a successful build was the release connected to Passenger and restarted.
- Before changing the domain, we checked PL, EN, the case studies, media, redirects, 404s, headers and access to Next.js assets.
The hosting had one more limitation: compilation could fail with an error when creating a thread pool (EAGAIN). So we limited the number of threads and worker pools for the build process. It was not “code optimisation”, just adapting the process to the limits of shared hosting.
The domain, HTTPS and the way back
Before switching production, we wanted to confirm the application on the target host without a public DNSThe system that translates a domain name, such as startify.space, into a server address. Changing DNS records decides which server responds at a given address. change. That is what an HTTPS test is for: it forces a specific IP address while keeping the correct domain name and certificate.
The first publishing attempt was rolled back, because a tool on the hosting could not correctly verify the TLSThe protocol that encrypts the connection; it is the “S” in HTTPS. The TLS certificate chain confirms that the server really belongs to the domain. chain. We did not work around the problem with a flag that disables verification. We checked an explicit CA certificate file and kept the rule: if HTTPS does not pass proper validation, we do not switch traffic.
The DNS change plan was deliberately narrow: change only the record that directs WWW traffic, leaving the name servers, email, TXT records and the development subdomain unchanged. The old Framer website and the previous records remained the way back. We did not replace the whole of public_html, because it also contained other parts of the infrastructure.
After the switch, www.startify.space is a CNAMEA DNS record saying that one domain name is an alias of another. Here, www.startify.space points to startify.space. record pointing to startify.space, and both addresses lead to the same server and respond over HTTPS. The canonical tag on both host variants points to https://www.startify.space, and the old Framer addresses are covered by permanent redirects.
Step 7. Google Analytics only after consent
A GA4Google Analytics 4, the current version of Google Analytics. A GA4 stream is the source of traffic data from one website; here we reused the existing Startify stream. stream was already running on the old website. Instead of creating a new property, we used the existing Startify stream and its measurement ID. We kept enhanced measurement and left page views to Google’s mechanism, without manually duplicating page_view on every change in React.
Analytics does not load automatically. The default state is no consent. Until the user accepts the Analytics category:
- the GA script is not added,
- there is no
preconnectto Google, - the browser does not send analytics pings.
The consent panel is bilingual and offers rejecting, customising and accepting. The choice is stored locally for 180 days. A read error, no access to storage or an expired choice means no consent, not consent by default.
Users can return to the settings later from the footer. Withdrawing consent removes the _ga and _ga_* cookies, disables analytics and reloads the document to remove the active listeners of the external script. The state is synchronised between tabs.
In addition, we limited data sending to startify.space and www.startify.space. Localhost and staging do not send data even after consent is given. Google Signals and ad personalisation remained disabled, and advertising consents were set to denied.
The analytics tests used a mock of Google. They checked both language versions, no connections before consent, accepting, rejecting, refreshing, withdrawing, clearing cookies, expired consent, blocked storage, synchronisation between tabs and the exclusion of localhost.
What AI actually did in this process
AI did not design my brand for me and did not decide what I should show to clients. Nor was it given the right to publish changes on its own.
Codex and Claude helped with four kinds of work:
- Analysis — making an inventory of the pages, DOM measurements, comparing Figma with the implementation, analysing fonts, assets and the change history.
- Implementation — components, styles, data models, language versions, tests, server launchers and analytics.
- Control — linting, types, builds, browser, visual and accessibility tests, checking the task scope and reporting discrepancies.
- Project memory — documenting decisions, errors, base points, risks and ways to reproduce the work.
The biggest advantage was not that code was produced faster. More important was that we could analyse more variants, record more knowledge and automate checks that are easy to skip in a one-person project.
At the same time, every time AI was given too broad a scope, the risk increased. That is why the faster a tool can work, the more important boundaries, change history and tests become.
How to repeat this process in your own project
The order below matters more than any particular framework.
Define roles and permissions
Write down who makes product decisions, who coordinates, who implements and who can publish. If you work with several agents, do not let them change the same files without coordination.
Result: a short rules file in the repository.
Build a map of the sources of truth
List all the sources: production, Figma, content, assets, analytics, the domain and the owner’s decisions. For each one, specify what we trust it for: the look, behaviour, content or history.
Result: an audit of routes, sections, fonts, breakpoints, assets, integrations and open decisions.
Secure the state before development
Create a repository, a first commit and a remote copy. Do not start several agents working on a set of untracked files.
Result: an unambiguous base commit and a clean tree.
Extract the system from the design
Before you build complete views, record the colour tokens, typography, grid, margins, breakpoints, buttons, lines and rules for cropping media.
Result: a small set of shared primitives instead of hundreds of local fixes.
Implement in vertical slices
Choose one section or route. Measure, implement, compare at several widths and only then move on. Write down the measurement traps.
Result: each stage can be accepted or reverted independently.
Separate content from components
Keep projects, copy, tags and galleries in a data model. The same component should be able to render further case studies without copying the whole page.
Result: simpler language versions and fewer inconsistencies.
Add tests before you start “polishing”
The minimum is linting, types and a build. For important interactions, add browser tests. For layout, check the widths on both sides of each breakpoint, not just popular devices.
Result: the next prompt does not quietly undo an earlier decision.
Treat SEO, accessibility and media as part of the product
Check metadata, canonicals, languages, redirects, 404s, contrast, keyboard use, reduced motion, image sizes and when videos load.
Result: the website is more than a nice screenshot.
Build staging with a rollback
Put releases in new directories. Keep the launcher and the configuration of the previous version. Protect staging with a password and
noindex. Build dependencies on the target operating system.Result: a failed build does not take down the working website.
Separate publishing from the DNS change
First run and check the application on the target server. Then verify HTTPS for the real domain without a public switch. Only at the very end change the minimum set of DNS records.
Result: the domain is not a tool for testing an unverified release.
Launch analytics deliberately
Check whether you are using an existing stream, which events are automatic and whether you are duplicating page views. Do not load the external script before consent if your privacy model requires it. Exclude staging and localhost.
Result: clean data and fewer accidental privacy breaches.
Prompts that work better than “build me a website”
Audit prompt
Analyse the existing website and design, but do not write any code yet. Prepare a list of routes, sections, components, fonts, colours, breakpoints, assets, interactions, integrations and open decisions. For each finding, give the source: production, Figma, local material or an owner’s decision. If the sources differ, do not choose on your own. Describe the discrepancy and its impact.
Section implementation prompt
Implement only the [name] section based on commit [SHA]. Permitted files: [list]. Out of scope: content, other sections, hosting. Recreate the layout for the widths [list] and the behaviour at the breakpoint boundaries. Do not guess missing values. Describe every deliberate difference from the reference. At the end, run [list of tests] and hand over a report: changed files, check results, manual QA, risks and the state of the working tree.
Review prompt
Compare the result with the brief and the base commit. Look for regressions, out-of-scope changes, unconfirmed assumptions, responsive issues, accessibility, SEO and performance. Do not fix the code. First present the findings by severity, with concrete evidence and a proposed way to verify each one.
The most important lessons
AI coding does not remove the need for project management. On the contrary: as implementation speeds up, precisely defining scope and responsibility becomes more and more important.
A live website is a separate source of knowledge. Figma shows the intent, but it does not always contain every breakpoint, state, animation and implementation compromise.
A measurement can be wrong too. Animations, hidden variants and export limitations can produce very convincing but false data.
Documentation is the memory of a team of agents. Chat helps you work, but only a commit, a decisions file and a handoff report let you continue a project safely.
Tests are not a stage after coding. They are a way of making further changes without constantly going back to square one.
Deployment is part of the product. The server, certificate, DNS, redirects, staging, rollback and analytics have as much impact on the result as React components.
Would I do it the same way again?
Yes, but with one change: I would create the repository, the base point, the role rules and the basic tests on the first day, before the first large batch of implementation.
The idea of combining two agents worked very well, because they did not try to do the same thing. One helped run the process and check the result, the other carried out clearly defined tasks, and I remained the person responsible for the product.
So the new startify.space is not so much “a website made by AI” as a website built in a new model of collaboration. AI wrote code, analysed, tested and documented. I set the direction, assessed the work and made the decisions.
And that is probably the most interesting answer to the question in the comment that started this article.
Terms from this article, explained in plain language
A
AI agent
An AI tool that does more than answer questions: it carries out tasks on its own, reading project files, changing code and running commands. In this project, the agents were Codex and Claude Code.
B
Basic Auth
The simplest password protection built into browsers: a login prompt appears before the page opens. Here it kept staging closed to accidental visitors.
Branch
A separate line of changes in a Git repository. Each task was built on its own branch, so it did not mix with other work until it was accepted.
Breakpoint
A screen width at which the page layout changes, e.g. from one column to two. In this article, these include the 810, 1280 and 1920 px thresholds.
C
Canonical
A tag in the page code that tells search engines the page’s main, preferred address. It helps when the same content is available at several addresses.
CDN
A network of servers around the world that deliver files, such as images, quickly. Framer served optimised copies of graphics through its CDN, which is why we preferred the originals.
CI
Continuous integration: an automated process that runs checks such as linting, the build and tests on every change in the repository, and reports errors.
Clean working tree
A state in which the local copy of the project has no changes that are not saved in Git. Starting from a clean tree makes sure no accidental edits end up in the task.
CNAME
A DNS record saying that one domain name is an alias of another. Here, www.startify.space points to startify.space.
Commit
A saved state of file changes in the Git history, with a description and an author. The base commit is a task’s starting point: the result is compared against it.
D
DNS
The system that translates a domain name, such as startify.space, into a server address. Changing DNS records decides which server responds at a given address.
DOM
The structure of a page that the browser builds from HTML and uses for display and scripts. We read the real sizes and behaviour of elements on the live website from the DOM.
G
GA4
Google Analytics 4, the current version of Google Analytics. A GA4 stream is the source of traffic data from one website; here we reused the existing Startify stream.
H
hreflang
A tag that tells search engines a page has versions in other languages and where they are. It links the Polish and English equivalents of the same page.
L
Launcher
A small start-up file that runs the application on the server and points to the version of the site it should serve. Separate launchers let staging and production be configured differently.
Linting
Automatically checking code for errors and style inconsistencies without running the site. It is one of the first gates before the build.
Lockfile
A file that records the exact versions of every package the project uses. It makes the computer, the agent and the server install exactly the same set.
M
Merge
Combining the changes from one branch into another, usually into the main version of the project. In this process, a merge required the owner’s separate approval.
N
Next.js
A framework for building websites and applications with React. Among other things, it provides routing, server-side page generation and a build ready for publishing.
noindex
An instruction telling search engines not to add a page to their results. Here it was used for the technical menu, error pages and staging, among others.
P
Phusion Passenger
Software on the hosting server that runs the Node.js application, looks after its process and passes browser traffic to it.
Playwright
A tool for automatically testing websites in real browsers: it clicks, scrolls, types and checks the result the way a user would.
Push
Sending local commits to a remote repository, such as GitHub. From then on, others can see the changes and automation can pick them up.
R
Repository
The place where Git stores the project files together with their full history of changes. A remote copy, e.g. on GitHub, protects the work and makes collaboration easier.
Rollback
Going back to the previous working version after a failed release. Here it was enough to restore the previous launcher, without rebuilding the site.
S
Staging
A test copy of the website on a real server, hidden from visitors and search engines. It lets you check a release before it goes live on the real domain.
T
TLS
The protocol that encrypts the connection; it is the “S” in HTTPS. The TLS certificate chain confirms that the server really belongs to the domain.
W
WCAG
The international Web Content Accessibility Guidelines. Among other things, they cover contrast, keyboard use and text for screen readers.
Webpack and Turbopack
Tools that, during the build, bundle and optimise the site’s code into a version ready for publishing. Turbopack is the default in Next.js, but Webpack worked on the hosting.