Cleanup of SaaS code (#6669)

# Description of Changes
De-AI comments and fix ridiculously indented code
This commit is contained in:
James Brunton
2026-06-16 11:49:13 +01:00
committed by GitHub
parent 42c1cce56d
commit 9a883be697
20 changed files with 79 additions and 99 deletions
@@ -24,6 +24,7 @@ import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtValidators;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.server.resource.OAuth2ProtectedResourceMetadata;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.web.authentication.BearerTokenAuthenticationFilter;
@@ -201,40 +202,9 @@ public class McpSecurityConfig {
.protectedResourceMetadata(
prm ->
prm.protectedResourceMetadataCustomizer(
builder -> {
if (!auth.getResourceId()
.isBlank()) {
builder.resource(
auth
.getResourceId());
}
if (!auth.getIssuerUri()
.isBlank()) {
builder.authorizationServer(
auth
.getIssuerUri());
}
// Only advertise the granular
// tool scopes when we actually
// enforce them. When scopes are
// disabled (e.g. the IdP only
// mints coarse tokens, like
// Supabase), advertising scopes
// the authorization server
// can't
// issue makes spec-compliant
// clients request them and get
// rejected with
// invalid_request.
if (applicationProperties
.getMcp()
.isScopesEnabled()) {
builder.scope(
"mcp.tools.read");
builder.scope(
"mcp.tools.write");
}
}))
builder ->
buildResourceMetadata(
builder, auth)))
.jwt(
jwt ->
jwt.decoder(mcpJwtDecoder)
@@ -243,6 +213,25 @@ public class McpSecurityConfig {
return http.build();
}
/** Populate the RFC 9728 protected-resource metadata document from the configured auth. */
private void buildResourceMetadata(
OAuth2ProtectedResourceMetadata.Builder builder, ApplicationProperties.Mcp.Auth auth) {
if (!auth.getResourceId().isBlank()) {
builder.resource(auth.getResourceId());
}
if (!auth.getIssuerUri().isBlank()) {
builder.authorizationServer(auth.getIssuerUri());
}
// Only advertise the granular tool scopes when we actually enforce them. When scopes are
// disabled (e.g. the IdP only mints coarse tokens, like Supabase), advertising scopes the
// authorization server can't issue makes spec-compliant clients request them and get
// rejected with invalid_request.
if (applicationProperties.getMcp().isScopesEnabled()) {
builder.scope("mcp.tools.read");
builder.scope("mcp.tools.write");
}
}
@Bean
JwtDecoder mcpJwtDecoder() {
ApplicationProperties.Mcp.Auth auth = applicationProperties.getMcp().getAuth();
@@ -303,9 +303,9 @@ public class PaygWalletController {
} else {
long capMinor = CapMoneyUnits.usdToCents(req.capUsd());
policy.setCapSourceMoney(capMinor);
// Derived document allowance (design §10: store both the money intent and the unit
// translation). The live snapshot recomputes from cap_source_money + current rate;
// this stored value is the enforcement fallback when the rate is unreachable.
// Derived document allowance: store both the money intent and the unit translation.
// The live snapshot recomputes from cap_source_money + current rate; this stored value
// is the enforcement fallback when the rate is unreachable.
TeamBillingContext billing = billingService.forTeam(teamId);
Optional<Long> docCap = billingService.docCapForMoney(billing, capMinor);
if (docCap.isPresent()) {
@@ -82,8 +82,7 @@ public record WalletSnapshotResponse(
/**
* One row of the team-members table on the leader's Plan page — display-only per-member usage.
* (Per-member sub-caps aren't enforced yet; see the follow-ups note. When they ship, a cap
* field returns here.)
* (Per-member sub-caps aren't enforced yet. When they ship, a cap field returns here.)
*/
public record MemberRow(String userId, String name, String email, int spendUnits) {}
@@ -12,7 +12,7 @@ import stirling.software.saas.payg.model.FeatureSet;
* effect, and the corresponding enabled {@link FeatureGate}s. No DB access, no caches — the caller
* (entitlement service) supplies the inputs.
*
* <p>State transitions (matching {@code notes/PAYG_DESIGN.md} §3.6):
* <p>State transitions:
*
* <ul>
* <li>{@code capUnits == null} → {@code FULL} / {@link FeatureSet#FULL} unconditionally.
@@ -78,10 +78,7 @@ public final class CapEvaluator {
return full();
}
/**
* Default enabled gates for a given feature set. Kept in sync with the design doc §3.7 mapping
* table.
*/
/** Default enabled gates for a given feature set. */
public static List<FeatureGate> gatesFor(FeatureSet set) {
if (set == null) {
return List.of();
@@ -20,17 +20,17 @@ import lombok.extern.slf4j.Slf4j;
/**
* Read-only accessor for the Stripe Sync Engine schema ({@code stripe.*}). Gives the PAYG layer the
* team's real billing window and the per-document rate of the Price its subscription bills against
* both live in Stripe, mirrored into Postgres by the sync engine, and are NOT duplicated in
* {@code stirling_pdf} (design §10: money lives in Stripe).
* - both live in Stripe, mirrored into Postgres by the sync engine, and are NOT duplicated in
* {@code stirling_pdf} (money lives in Stripe).
*
* <p>PAYG prices are plain {@code per_unit} metered prices, so {@code stripe.prices.unit_amount}
* carries the rate directly. The free grant is deliberately NOT in Stripe it's the one-time
* carries the rate directly. The free grant is deliberately NOT in Stripe - it's the one-time
* {@code pricing_policy.free_tier_units} pool, applied app-side (free units are never metered),
* because un-subscribed teams get the same grant and have no Stripe Price at all.
*
* <p>Defensive by construction: the {@code stripe} schema only exists where the sync engine has run
* (dev + prod Supabase, not unit-test H2). Any {@link DataAccessException} missing schema,
* missing row, connectivity blip degrades to {@link Optional#empty()} with a WARN so callers fall
* (dev + prod Supabase, not unit-test H2). Any {@link DataAccessException} - missing schema,
* missing row, connectivity blip - degrades to {@link Optional#empty()} with a WARN so callers fall
* back to calendar-month windows rather than 500ing the wallet endpoint.
*/
@Slf4j
@@ -60,13 +60,13 @@ public class StripeSubscriptionDao {
BigDecimal perDocMinor) {}
/**
* The per-document rate of a Price looked up directly (not via a subscription) used to price
* The per-document rate of a Price looked up directly (not via a subscription) - used to price
* the cap estimate for un-subscribed teams, whose default policy points at Stripe Prices that
* carry the same {@code unit_amount} they'd be billed at on subscribing.
*
* @param priceId the resolved Stripe Price id
* @param currency lower-case ISO 4217 of that Price
* @param perDocMinor per-document rate in minor units (may be fractional); never null a row
* @param perDocMinor per-document rate in minor units (may be fractional); never null - a row
* with no usable amount is filtered out rather than returned with a null rate
*/
public record PriceRate(String priceId, String currency, BigDecimal perDocMinor) {}
@@ -130,12 +130,12 @@ public class StripeSubscriptionDao {
/**
* Per-document rate of the active {@code stripe.prices} row with the given {@code lookupKey} in
* {@code currency} the elegant mirror of {@link #findBilling}, reading the same synced table
* {@code currency} - the elegant mirror of {@link #findBilling}, reading the same synced table
* by Stripe Price {@code lookup_key} instead of via a subscription. The PAYG layer uses this to
* price the cap estimate for an un-subscribed team: there's no subscription to read a rate off,
* but the PAYG Price (lookup key {@code plan:processor}) carries the very rate they'd be billed
* at. We resolve by lookup_key rather than the default policy's price ids because those aren't
* seeded the lookup key is the stable, env-agnostic handle (same one the price-lookup edge
* seeded - the lookup key is the stable, env-agnostic handle (same one the price-lookup edge
* function uses).
*
* <p>Empty when the {@code stripe} schema is absent (H2 unit tests), no active matching row
@@ -9,8 +9,6 @@
-- restored on a first-step refund). Because the counter is authoritative, the wallet_ledger is
-- no longer the source of truth for the grant and its old rows can be pruned after a retention
-- window (separate future job).
--
-- See notes/payg-lifetime-free-grant-plan-2026-06-11.html.
-- ---------------------------------------------------------------------------------------------
-- 1. Rename the policy column — it is no longer "per cycle", it's the one-time grant size.