Getting Started with qqq: Your First App in 30 Minutes

Learn how to build a complete CRUD application with authentication, audit trails, and a dashboard in under 30 minutes using the qqq framework.

Getting Started with qqq: Your First App in 30 Minutes

This tutorial walks you through building a complete application with qqq. By the end, you'll have a working app with CRUD operations, a REST API, authentication, and an admin UI.

The qqq framework allows you to define your entire application through metadata, eliminating the need for boilerplate code while maintaining full control over your business logic.

Prerequisites

You'll need:

  • Java 21 or later
  • Maven 3.8+
  • Your favorite IDE (IntelliJ recommended)

Step 1: Create Your Project

Start with our Maven archetype:

bash
mvn archetype:generate \
  -DarchetypeGroupId=io.qrun \
  -DarchetypeArtifactId=qqq-quickstart \
  -DgroupId=com.example \
  -DartifactId=my-app

This creates a project with qqq dependencies configured and a sample application structure.

Step 2: Define Your First Table

Create a table for customers. In src/main/java/com/example/metadata/CustomerTableMetaData.java:

java
public class CustomerTableMetaData implements MetaDataProducerInterface<QTableMetaData> {
 
   public static final String TABLE_NAME = "customer";
 
   @Override
   public QTableMetaData produce(QInstance qInstance) {
      return new QTableMetaData()
         .withName(TABLE_NAME)
         .withBackendName("default")
         .withPrimaryKeyField("id")
         .withFields(List.of(
            new QFieldMetaData("id", QFieldType.INTEGER),
            new QFieldMetaData("name", QFieldType.STRING)
               .withIsRequired(true)
               .withMaxLength(100),
            new QFieldMetaData("email", QFieldType.STRING)
               .withIsRequired(true),
            new QFieldMetaData("createdAt", QFieldType.DATE_TIME)
         ));
   }
}

That's it. This single class gives you:

  • Database table creation
  • Insert, update, delete, and query operations
  • REST API endpoints (/api/customer)
  • OpenAPI documentation
  • Admin UI with search, forms, and validation

Step 3: Add Another Table with Relationships

Add an orders table that links to customers:

java
public class OrderTableMetaData implements MetaDataProducerInterface<QTableMetaData> {
 
   public static final String TABLE_NAME = "order";
 
   @Override
   public QTableMetaData produce(QInstance qInstance) {
      return new QTableMetaData()
         .withName(TABLE_NAME)
         .withBackendName("default")
         .withPrimaryKeyField("id")
         .withFields(List.of(
            new QFieldMetaData("id", QFieldType.INTEGER),
            new QFieldMetaData("customerId", QFieldType.INTEGER)
               .withIsRequired(true),
            new QFieldMetaData("orderDate", QFieldType.DATE),
            new QFieldMetaData("total", QFieldType.DECIMAL),
            new QFieldMetaData("status", QFieldType.STRING)
               .withPossibleValueSourceName("orderStatus")
         ))
         .withRecordSecurityLock(new QRecordSecurityLock()
            .withFieldName("customerId"));
   }
}

Step 4: Configure Your Backend

In your application configuration, set up a database:

java
qInstance.addBackend(new QBackendMetaData()
   .withName("default")
   .withBackendType("RDBMS")
   .withConnection(new DatabaseConnection()
      .withDatabaseType(DatabaseType.POSTGRESQL)
      .withJdbcUrl("jdbc:postgresql://localhost:5432/myapp")
      .withUsername("myuser")
      .withPassword("mypassword")
   )
);

qqq supports PostgreSQL, MySQL, SQLite, MongoDB, and custom backends. Switch databases by changing the connection - your application code stays the same.

Step 5: Add Authentication

Enable authentication with a few lines:

java
qInstance.withAuthentication(new QAuthenticationMetaData()
   .withType(QAuthenticationType.TABLE_BASED)
   .withUserTableName("user")
);

This adds login/logout, session management, and user management. For OAuth2 or SAML, use the appropriate authentication type.

Step 6: Enable Audit Logging

Add audit trails to track all changes:

java
// On your table definition
.withAuditRules(new QAuditRules()
   .withAuditLevel(AuditLevel.RECORD))

Every insert, update, and delete is now logged with who made the change and when.

Step 7: Run Your Application

Start the development server:

bash
mvn compile exec:java

Open http://localhost:8000 to see your admin UI. Navigate to customers, create a few records, then check the audit log to see your changes tracked.

What You've Built

In about 30 minutes and ~100 lines of code, you have:

  • Two database tables with a relationship
  • Full CRUD operations for both
  • REST API with OpenAPI documentation
  • Admin UI with forms, search, and validation
  • User authentication
  • Audit logging for compliance

With traditional frameworks, this would require several thousand lines of code across dozens of files.

Next Steps

From here, you can:

  1. Add business logic: Create processes with custom steps
  2. Configure permissions: Set up role-based access control
  3. Customize the UI: Override generated components
  4. Deploy to production: Use qRun or self-host

Check out our documentation for deep dives on each topic, or try our weekend project tutorial to build a complete order management system.

Getting Help

Welcome to qqq. We can't wait to see what you build.

Read next

Ready to build faster?