Spring Boot · Apache Wicket · Spring Modulith · MongoDB · AI agents

Ship whole features with a team of three.

Most business software doesn't need a frontend team, a backend team and an API between them. With plain Java from the database to the button, two or three people can own every feature end to end, and AI agents take the routine work off their hands. fullstack4j is how allwerker, a Munich cooperative of senior engineers, sets up, staffs and coaches such teams.

One language, one deployable Architecture checked on every build Open source, Apache 2.0 Backed by 19 senior engineers at allwerker
Slices, not layers Three horizontal technical layers (UI, logic, data) are crossed by three vertical feature slices called ordering, billing and shipping. Each slice has one owner and contains its own page, service and repository. Slices talk to each other through events. UI Logic Data Page Service Repo Page Service Repo Page Service Repo ordering billing shipping slices talk through events · boundaries tested
One feature, one slice, one owner, from database to button.
The hidden cost

Your stack quietly decided your team size.

Choose a JavaScript single-page app, a REST API and a Java backend, and you have also chosen an org chart: frontend developers, backend developers, two build pipelines, and an API contract to negotiate for every feature. Each piece is reasonable on its own. Together they turn every user story into a relay race.

Split by technology

The usual setup

  • One feature becomes tickets in two or three backlogs, done by different people at different times.
  • Two languages, two build chains, two dependency treadmills to keep up with.
  • An API between your own UI and your own backend that no user ever asked for.
  • Work waits on whoever is the specialist for the layer that's next.
Split by feature

The fullstack4j setup

  • One feature is one slice, built and shipped by one person or pair.
  • Java and HTML templates. One build, one deployable, one set of dependencies.
  • The UI calls the service directly. Boundaries sit between features, where they matter.
  • Anyone on the team can pick up the next most valuable thing.
36
paths between 9 people
3
paths between 3 people

paths = n(n−1) / 2

Every line is a meeting, a handoff or a misunderstanding waiting to happen. Triple the team and you get twelve times the coordination. Adding people to a split stack mostly buys you more lines.

Removing the layers that force the split is the cheapest way to make a team smaller and faster.

The approach

Small teams. Whole features. Plain Java.

Nothing here is new or exotic. It is mature, well-documented technology, arranged so that a small team can understand the whole product and change any part of it safely.

01

Slices, not layers

Each feature lives in one package: its Wicket page, its service, its MongoDB documents and repository, and the events it publishes. One person or pair takes it from idea to production. There are no "frontend part" and "backend part" tickets.

02

One language, one deployable

Server-rendered UI with Apache Wicket: Java components and plain HTML templates, Ajax built in. No JavaScript build chain, no client state to sync, no API contract with yourself. One Spring Boot jar to test, ship and run.

03

Boundaries are tested, not documented

Spring Modulith turns each slice into a module, and ArchUnit adds the house rules. When code reaches into another slice, the build fails. Architecture stays intact while people, and agents, write code quickly.

04

AI as the fourth team member

A uniform, typed, well-tested codebase with enforced boundaries is where coding agents do their best work. People decide what to build and review the result; agents handle the routine work in between.

Anatomy of a slice

What a feature looks like when one person owns it.

Everything a feature needs, in one folder you can read in ten minutes. This is ordinary Wicket, Spring Boot and Spring Data MongoDB. The only rule is where things go.

src/main/java/com/acme/shop
shop/
├── ShopApplication.java
├── ordering/             one slice, one module
│   ├── OrdersPage.java    UI, plain Wicket
│   ├── OrdersPage.html    markup, no JS build
│   ├── OrderService.java  use cases
│   ├── Order.java         one MongoDB document
│   ├── Orders.java        MongoRepository
│   └── OrderShipped.java  event for others
├── billing/              listens to OrderShipped
└── shipping/

src/test/java/…/shop/
├── ArchitectureTests.java    Modulith + ArchUnit
├── TestShopApplication.java  dev run on MongoDB
└── ordering/
    └── OrderServiceTests.java  real MongoDB
Readable by anyone on the team. No frontend folder and backend folder to keep in sync.
Small enough for one head, and for one agent's context window.
Guarded by tests. billing can react to an order being shipped, but it can't reach into ordering's internals.
Stored as documents. An order and its lines are one MongoDB document, shaped like the code, so the schema grows with the slice instead of through migrations.
public class OrdersPage extends WebPage {

    @SpringBean
    private OrderService orders;

    public OrdersPage() {
        var list = new WebMarkupContainer("list");
        add(list.setOutputMarkupId(true));

        var open = LoadableDetachableModel.of(orders::open);
        list.add(new ListView<>("orders", open) {
            @Override
            protected void populateItem(ListItem<Order> item) {
                Order order = item.getModelObject();
                String id = order.id();
                item.add(new Label("customer", order.customer()));
                item.add(Oat.Components.button("ship", "Ship", ajax -> {
                    orders.ship(id);
                    Oat.toast(ajax, "Shipped", OatVariant.SUCCESS);
                    ajax.add(list);
                }));
            }
        });
    }
}
Built for working with agents

Boring technology is AI-friendly technology.

Coding agents are only as good as the feedback they get. A single typed language, fast tests and architecture rules that fail loudly give them exactly that, so a team of three can review more than it has to type.

You: shape the next piece→ Agent: drafts it→ Build: compiles, tests, checks boundaries→ You: review and ship

Guardrails, not guesswork

Modulith and ArchUnit tests catch an agent that wanders into the wrong module before a human has to.

One language in context

No TypeScript types drifting from Java DTOs. The agent sees the page, the service and the data in one place.

Feedback in seconds

The compiler, JUnit, Mockito and WicketTester check UI and logic without a browser, and Testcontainers gives every test run a real MongoDB.

Conventions as skills

Curated agent skills, such as those collected at jvmskills.com, teach agents how your team builds slices.

Beyond the code

The organisational dividend.

Fewer moving parts in the stack means fewer moving parts in the organisation. That is where most of the savings come from, and they are easy to overlook.

Conway's law, on purpose

Teams build systems shaped like their communication. Shape the team around features and the system follows the product, not the tech.

No waiting on specialists

No queue for "the frontend person". Whoever is free takes the next most valuable slice, so work keeps flowing.

One hiring profile

Java and Spring developers are easy to find and slow to burn out on churn. You hire for one skill set and grow it.

Talk about users, not APIs

With little coordination to manage and an appetite instead of estimates, conversations turn to outcomes and value, not story points.

Onboarding in days

A new colleague reads one slice, ships a change to it, and already understands how every other slice works.

Calm dependencies

Mature, slow-moving libraries mean fewer forced migrations, so maintenance doesn't crowd out the roadmap.

For engineering leaders

A team of eight to twelve for a workflow-heavy business application, and it still feels slow.

The same scope with two or three people, one skill set and far fewer moving parts to run.

For founders and product people

Coordination eats the roadmap. Every idea needs a meeting before it needs code.

From idea to a shipped slice in days, with a team that talks about your users.

For Java developers

Stuck "on the backend", switching contexts, and tired of JavaScript churn.

Own features end to end in the language you know, with agents doing the boilerplate.

How the team works

Fixed time, variable scope: a rhythm built for small teams.

Our teams work with the core ideas of Shape Up, the method Basecamp developed for small product teams. It fits the stack almost too well: its standard team is one designer and two programmers, and it builds front end and back end together, one piece at a time. With Wicket's plain HTML templates, the designer works in the same repository as everyone else.

Appetite, not estimates

Instead of estimating stories, decide how much time a problem is worth: two weeks or six. The date stays fixed and the scope flexes to fit it. No story points, no velocity charts.

Shaped before it's built

Experienced people shape the work first: the problem, a rough solution, the rabbit holes and what's out of scope. Agents build fast; shaping makes sure they build the right thing.

Whole scopes, one piece at a time

The team gets the whole problem, not a task list. Its scopes map naturally to slices and modules, and it gets one piece working end to end, page to database, first.

Bets, not backlogs

In each cool-down, decide which shaped pitches to bet on next. No backlog to groom. Work that doesn't ship within its cycle isn't extended by default; it gets reshaped.

Shape Up was written by Ryan Singer at Basecamp and is free to read at basecamp.com/shapeup. We use its core ideas and adapt the details to each team.

The toolbox

Small, open-source tools that take away the friction of day one.

The approach runs on standard Spring and Wicket. These helpers make the first hour pleasant and are deliberately small, so they are easy to understand and to keep up to date.

start.fullstack4j.dev

fullstack4j start

Everything start.spring.io offers, plus Apache Wicket. Our link comes with the fullstack4j defaults preselected: Wicket, MongoDB, Testcontainers and Spring Modulith.

dev.jbaby · wicket-spring-boot-starter

Wicket Spring Boot Starter

Apache Wicket 10 on Spring Boot 4 with a single dependency: auto-configured filter, @SpringBean injection, DevTools support. Small enough to read in one sitting.

dev.jbaby · wicket-oat

Wicket Oat

A modern, themeable component library for Wicket: forms, tables, dialogs, toasts and more, with accessible forms by default and light and dark themes.

terminal
curl https://start.fullstack4j.dev/starter.zip -d dependencies=wicket,data-mongodb,testcontainers,modulith -o shop.zip
unzip shop.zip && ./mvnw spring-boot:test-run   # the app on a throwaway MongoDB in Docker
Who's behind it

A cooperative of senior engineers, not a one-person show.

fullstack4j is an offering of allwerker eG, an IT cooperative founded in Munich in 2023. Its members are independent senior engineers, architects and consultants who run the cooperative together as equal partners. You work directly with the people who deliver.

allwerker
19senior engineers, architects and consultants
Since 2023a registered cooperative in Munich
Solo or as a teamone expert or a whole team, as you need

Full-stack & Java engineers

Build slices end to end, from the Wicket page to the database, with the habits that keep them clean.

Software architects

Domain- and event-driven design, sensible module cuts, and replacing legacy systems step by step.

Platform & cloud engineers

Run the one deployable wherever it fits: a single server with Docker and Kamal, or Kubernetes on AWS, Google Cloud or Azure.

Security & compliance

Secure development, identity and access management, ISO 27001 and GDPR, built in from the first slice.

AI & data

AI platforms, machine learning and data engineering for when the product needs more than coding agents.

Operations & stability

Monitoring, incident response and performance work, so the product stays up long after launch.

No single point of failure

A team of three can't afford to stall when one person is out. The cooperative covers absences and brings in a specialist for a week when a slice needs one.

Organised the way we ask you to work

Equal partners, shared responsibility, no middle management. The cooperative runs on the same principles as the small teams it builds.

A partner beyond the project

allwerker aims for long-term partnerships, so the people who set up your team are still around when you need them again.

Portrait of Daniel Bartl
Your first contact

Daniel Bartl leads fullstack4j at allwerker.

Software engineer and agile practitioner in Munich. In 2004 he founded a Java and Spring consultancy and grew it to more than a hundred people in self-managing teams without middle management, until it was acquired in 2021. He has organised the Lightweight Java User Group since 2010 and maintains the fullstack4j toolbox.

20+ yearsbuilding on the JVM
100+ peoplecompany built on self-managing teams
Since 2010running a Java user group
Work with allwerker

Set up the team with us, or let us be the team.

Tools are the easy part. What makes a small team work is a shared way of slicing the product, a few firm conventions and the habit of shipping in small steps. allwerker builds that with your people, and brings its own engineers whenever you need more hands.

1–2 days

Fit check

A workshop on your product and your team. We map the domain into slices with Event Modeling, shape the first pitch, look at what you already run, and give you an honest go or no-go.

A slice map, a first shaped pitch and a clear decision.
Up to 6 weeks

First cycle

We set up the repository, modules, architecture tests, CI, hosting and agent conventions, and ship the first shaped project within its appetite, together with the people who will own it.

A running product and a team that knows how to shape and ship the next piece.
Ongoing, part-time

Run & coach

We stay on as pairing and mob partners, or as the team itself, running the cycles with you: shaping, betting, building, cool-down. You decide how far we step back.

A team that keeps its pace, with or without us.

Who builds it

The method stays the same. Who writes the code is up to you.

Your team, coached

Your developers build the product. allwerker sets up the skeleton, pairs and coaches, and steps back as your team takes over.

Mixed team

One or two allwerker engineers join your people, fill the gaps and pass the habits on by working side by side.

allwerker team

A complete team of three from the cooperative builds your product, then hands it over or keeps running it, as you prefer.

In preparation

Trainings

Hands-on courses for teams that want to learn the approach on their own terms, as part of allwerker's training and workshop offering. Get notified when the first dates are set.

Notify me
  • Apache Wicket for Spring developers 1 day
  • Modular monoliths with Spring Modulith & ArchUnit 1 day
  • AI-assisted vertical-slice delivery 1 day
Honest fit

When it's the right call, and when it isn't.

No approach fits everything. Here is where this one shines and where we'd tell you to choose something else.

A great fit

  • Business applications, internal tools, B2B SaaS, back-office and portals
  • Products full of forms, tables, workflows and rules
  • Teams with Java skills, or a JVM landscape they want to build on
  • Legacy systems you want to replace slice by slice

Probably not

  • Offline-first apps or real-time collaborative editors
  • Consumer apps that need to feel native on every device
  • Content and marketing sites, where a static site generator is simpler
  • Teams with no JVM experience and no wish to build it
FAQ

Questions we hear a lot.

Who will actually work with us?

Daniel Bartl leads fullstack4j and is your first contact. The engineers come from allwerker, chosen for what your product needs: full-stack and Java engineers for the slices, platform and cloud engineers to run them, and security or data specialists when a slice calls for it. You work with them directly.

Do you work in sprints?

We work in Shape Up-style cycles: shaped work, a fixed time box and a cool-down in between. If your organisation runs Scrum or Kanban, we adapt. The slice structure works with any of them.

Isn't Apache Wicket old technology?

It is mature: an Apache project with two decades of production use. Wicket 10 runs on Java 17+, Jakarta EE 10 and the current Spring Boot. "Old" mostly means it has kept working while other frameworks were rewritten. That is exactly what you want under a product you plan to keep for ten years.

Can a server-rendered UI feel modern?

Yes. Wicket updates parts of a page via Ajax without you writing JavaScript, and Wicket Oat gives you modern, themeable, accessible components. Where a page really needs a rich client widget, such as a chart, a map or an editor, you embed it into that page and leave the rest alone.

Why MongoDB and not a relational database?

A slice's data usually has one natural shape, like an order with its lines. MongoDB stores it as one document, exactly as the code models it, so the schema grows with the slice instead of through migration scripts. Testcontainers gives every developer and every CI run a real MongoDB, with nothing to install. If your domain is strongly relational or the database is already decided, Spring Data JPA fits the same slice structure.

What happens when we grow beyond three people?

Modules become team boundaries. Add a second small team that owns a group of slices, not a layer. Spring Modulith keeps the boundaries explicit, so if a module ever really needs to become its own service, the cut is already there.

We already run a SPA and microservices. Do we start over?

No. New slices go into a modular application next to what you have, and old parts are replaced one at a time when there's a reason to touch them. Incremental modernisation of legacy systems is part of what we do.

Why Wicket and not Vaadin or HTMX?

Both are good choices with the same philosophy, and we're happy to talk about them. We prefer Wicket for its plain HTML templates, its strong component model and how easy it is to unit-test UI with WicketTester.

How much lock-in is there?

Very little. Everything is Apache-licensed open source, and the fullstack4j helpers are thin on purpose. You can drop them at any time and keep plain Wicket and plain Spring Boot.

Do we have to use AI agents?

No. The approach stands on its own and was useful long before coding agents. Agents make a small team even more effective, and the architecture tests make them safe to use. How far you go is up to you.

Let's talk

Could your next product be built by a team of three?

Tell us what you're building and who's building it. We'll tell you honestly whether this approach fits, where we'd start, and who from allwerker should be involved.