Page 1 of 19
System Requirements Document for konter-depriyan-cell
1. Introduction
konter-depriyan-cell is a web application for a neighbourhood digital top-up counter (konter) in Indonesia. The product exists so that a walk-in customer can order a digital top-up — pulsa, kuota (data package), token PLN, or game credits — and have it handled fast, while the shop owner / counter operator processes those orders and keeps stock levels accurate. Speed of transaction is the core value of the product.
The application is delivered as hand-authored HTML, CSS, and JavaScript with a database backing it, as explicitly requested by the project owner (depriyan manggari). It is a first-party application with its own identity and its own custom interface; it is not a wrapper around a third-party provider's screen.
The audience is two accepted human roles:
- Shop Owner / Counter Operator — runs the counter, processes incoming top-up orders, and tracks stock.
- Customer — places a top-up order and expects it to be completed without friction.
The reference site https://konter-kilat-topup.base44.app/ is used only as domain context: it establishes the top-up counter domain and the four service lines (pulsa, kuota, token PLN, top-up game). It could not be opened during planning, so none of its features, flows, or behaviours are treated as confirmed, and nothing from it is copied into this product.
Page 2 of 19
2. System Overview
konter-depriyan-cell is a small, fast, single-purpose counter application. It has six first-party pages: a public Landing page that states what the counter sells, a Login and a Sign Up page that establish and verify identity, an Order Form where a customer submits a top-up order, an Orders workspace where the operator reviews and processes submitted orders, and a Stock workspace where the operator tracks and updates stock for the top-up products.
The system is built from plain HTML, CSS, and JavaScript on the client, with a database on the server side that durably stores accounts, orders, and stock. Because orders and stock must survive a page reload and must remain bound to the correct person, the application owns identity: a person signs up once, logs in on return, and then sees their own orders or the operator workspaces according to their role.
The four service lines are colour-coded throughout the interface as a wayfinding system: pulsa, kuota, token PLN, and top-up game each carry their own flat poster colour, and that code is reused on chips, table row accents, filter tabs, and status stamps.
Narrow exclusions. This document does not add payment-gateway integration, delivery of the top-up through a third-party operator API, customer-facing chat, loyalty programmes, multi-branch management, or reporting/analytics beyond what the accepted order and stock workflows require. The reference site's internal features are unverified and are not treated as requirements.
Page 3 of 19
2a. Product Interpretation and Delivery Boundary
Delivery ownership. The application is first-party and self-contained. The client is hand-written HTML, CSS, and JavaScript; the server side persists to a database. There is no accepted provider-owned surface and no accepted external destination for the core work — the counter's own pages own the ordering, processing, and stock work.
Access ownership. The Landing page is publicly reachable and anonymous: it explains the counter and its four service lines to anyone who arrives. Login and Sign Up are also anonymously reachable, because a protected page cannot own the interaction that grants access to itself. The Order Form, Orders, and Stock pages are protected: they hold durable, person-specific state (a customer's own submitted orders; the operator's order queue and stock levels), so they require an established identity before they can be used. Sign Up is self-service — no invitation or provisioning boundary was established by the source, so a person creates their own account.
Role boundary. The accepted scope distinguishes customer order access from counter-operator order processing and stock control. The Order Form belongs to the customer's side of the counter; Orders and Stock belong to the operator's side. This is a role-aware boundary over shared product state, not a general permission system.
Current vs. future. Everything described in this document is current. No future-horizon features were accepted; the reference site's unverified contents are explicitly not a current commitment.
Page 4 of 19
2b. Source Content Inventory
Not applicable. The reference directive for https://konter-kilat-topup.base44.app/ declares uses: ["domain_context", "feature_reference"] and does not declare content_source, so no source content inventory is produced. The only verified facts carried forward from that reference are the domain context (top-up counter domain) and the four service lines: pulsa top-up, kuota (data packages), token PLN (electricity tokens), and top-up game (game credits).
2c. Page Content and Component Coverage
Landing
- Information / state: The counter's identity as a poster masthead — "KONTER DEPRIYAN CELL" set full-bleed in Anton, flush left, leading 0.86. A continuously scrolling service marquee band naming the four service lines: PULSA • KUOTA • TOKEN PLN • TOP-UP GAME. Four colour-coded service panels, one per product line, each stating what the counter sells. No account state is required to read any of it.
- Primary actions: "ORDER SEKARANG" — a solid yellow rectangle with black Anton text, pinned to the bottom-left of the hero, overlapping the red marquee band by 24px so it reads as a screen-printed sticker. It leads to the Order Form for a signed-in customer, and to Login for anyone else.
- Supporting actions: "MASUK" (go to Login) and "DAFTAR" (go to Sign Up) in the top bar.
- Domain entities: Service category (pulsa, kuota, token PLN, top-up game) with its assigned colour code.
- Component responsibilities: Full-bleed typographic masthead; service marquee band; four flat colour-blocked service panels with 3px-stroke pictograms (signal bars, data arrows, lightning bolt, gamepad); 6-degree diagonal colour bands slicing section transitions; top bar with a hard 2px rule beneath it.
- States: Loading — static markup, no data fetch required; the marquee begins immediately. Empty — not applicable, the four service lines are fixed content. Success — the page renders its full poster composition. Error — if the session check that decides whether "ORDER SEKARANG" routes to the Order Form or to Login fails, the button falls back to routing to Login and the page remains fully readable. Recovery — the visitor can always reach Login or Sign Up from the top bar.
Login
- Information / state: A returning-verification form. Fields: email/username and password. Anonymous access — this page is reachable without an identity, because it is the page that establishes one.
- Primary actions: Submit credentials to verify identity and continue to the destination the person was trying to reach (Order Form for a customer, Orders for an operator).
- Supporting actions: Link to Sign Up for a person who has no account yet; link back to Landing.
- Domain entities: Account (identity), role (customer or operator).
- Component responsibilities: Poster-scale page heading in Anton; ruled form fields in Archivo; a solid flat submit button with a 3px hard offset shadow in the opposite poster colour; an inline error region.
- States: Loading — the submit button shows a processing state while verification runs. Empty — fields start empty with visible labels. Success — identity is verified and the person is routed to the page they came for. Error — wrong credentials or an unverified account produce an inline message in the error region; the form retains the entered identifier so the person can correct only the password. Recovery — the person can retry, or switch to Sign Up.
Page 5 of 19
Sign Up
- Information / state: A self-service enrollment form. Fields: name, email/username, password, and the role the person is enrolling as (customer or counter operator). Anonymous access.
- Primary actions: Create the account and establish identity.
- Supporting actions: Link to Login for a person who already has an account; link back to Landing.
- Domain entities: Account (identity), role (customer or operator).
- Component responsibilities: Poster-scale heading; ruled form fields; role selection presented as two full-bleed rectangular category bands (not pills); a solid flat submit button with a 3px hard offset shadow; an inline error region.
- States: Loading — the submit button shows a processing state while the account is created. Empty — fields start empty with visible labels. Success — the account is created and the person continues into the application as their chosen role. Error — a duplicate identifier or a missing required field produces an inline message naming the field; the form retains everything already typed. Recovery — the person can correct the field and resubmit, or switch to Login if the account already exists.
Order Form
- Information / state: A focused order-entry flow for a signed-in customer. It shows the four service categories as full-bleed rectangular colour bands (pulsa = red, kuota = yellow, token PLN = teal, top-up game = off-white on red), the selected category's destination field (phone number, PLN meter/customer ID, or game account ID), and the nominal/denomination options available for that category. Protected — requires an established identity.
- Primary actions: Select a service category, enter the destination, choose a nominal, and submit the order.
- Supporting actions: Change the selected category before submitting; clear the form; navigate to the customer's own order list to see previously submitted orders.
- Domain entities: Order (id, category, destination, nominal, status, created timestamp, owning account), Service category, Product/nominal.
- Component responsibilities: Category band selector; ruled destination input; nominal selector rendered as a ruled list with tabular-figure prices; a solid flat submit button with a 3px hard offset shadow; a confirmation panel that stamps in with a 120ms scale-from-1.06 snap.
- States: Loading — the nominal list for the chosen category loads; the submit button is disabled until a category, destination, and nominal are all present. Empty — before a category is chosen, the form shows the four category bands and nothing else; if a chosen category has no available nominals, the form states that plainly and keeps the category switchable. Success — the order is created and the customer sees its order ID and a "PROSES" status stamp in yellow. Error — a missing or malformed destination, or a submission that fails to persist, produces an inline message and keeps every entered value so the customer can retry without retyping. Recovery — the customer can correct the field and resubmit, or switch category and start a different order.
Orders
- Information / state: The operator's revisitable workspace for submitted top-up orders. Rendered as a strict ruled tabular grid: order ID, category (with its colour code as a row accent), destination, nominal, customer, created timestamp, and status. Status is set as a rotated -3deg stamp — "PROSES" in yellow, "SELESAI" in red, "BATAL" in muted. Protected — requires an established operator identity.
- Primary actions: Open an order and change its status to SELESAI (completed) or BATAL (cancelled).
- Supporting actions: Filter the list by status and by service category using the four-colour filter tabs; sort by created time; refresh the queue.
- Domain entities: Order (id, category, destination, nominal, status, created timestamp, owning account), Account (customer).
- Component responsibilities: Ruled tabular rows with 2px rules and tabular-figure numerals; four-colour filter tabs; status stamps that snap in at 120ms; a row-level status control.
- States: Loading — the queue loads with ruled placeholder rows. Empty — when no orders match the current filter, the workspace states that plainly and offers to clear the filter. Success — a status change is reflected immediately in the row's stamp and in the filter counts. Error — if a status change fails to persist, the row reverts to its previous stamp and an inline message explains the failure. Recovery — the operator can retry the status change or refresh the queue.
Page 6 of 19
Stock
- Information / state: The operator's workspace for tracking stock associated with top-up products. Rendered as a ruled tabular grid: product name, service category (with its colour code), nominal/denomination, current stock count in tabular figures, and last-updated timestamp. Protected — requires an established operator identity.
- Primary actions: Update a product's stock count.
- Supporting actions: Filter by service category using the four-colour filter tabs; sort by name, category, or stock count; identify low-stock rows.
- Domain entities: Product (name, category, nominal, stock count, last-updated timestamp), Service category.
- Component responsibilities: Ruled tabular rows with 2px rules; inline editable stock count in Archivo 700 with tabular figures; four-colour category chips; a low-stock emphasis using the category colour rather than a new colour.
- States: Loading — the stock table loads with ruled placeholder rows. Empty — when no products match the current filter, the workspace states that plainly and offers to clear the filter. Success — an updated count is reflected immediately in the row and its timestamp. Error — if an update fails to persist, the row reverts to its previous count and an inline message explains the failure. Recovery — the operator can retry the update or refresh the table.
Page 7 of 19
3. Functional Requirements
Each requirement is a distinct story point. Provenance is marked explicit (stated by the user or the accepted planning scope), basic_default (an accepted default filling an unspecified detail), or required_inference (an indispensable mechanic needed to make an accepted outcome usable).
FR-1 — Hand-authored HTML, CSS, and JavaScript with a database (explicit)
As the project owner, I should have the application delivered as hand-written HTML, CSS, and JavaScript backed by a database, so that the counter app is a self-contained first-party product I can run and own.
- Trigger/input: The project is built and deployed.
- Observable result: The client is plain HTML/CSS/JS; accounts, orders, and stock are persisted in a database and survive a page reload.
- Access state: Not applicable to the build itself.
- Failure/recovery: If the database is unreachable, the application surfaces an error state on the affected page rather than silently discarding the person's input.
- Continuation: The person can retry the action once the database is reachable.
FR-2 — Four service lines are offered (explicit, from domain context)
As a customer, I should be able to order any of the counter's four service lines — pulsa, kuota (data package), token PLN, and top-up game — so that the counter covers the digital top-ups I actually need.
- Trigger/input: The customer selects a service category on the Order Form.
- Observable result: The form shows the destination field and nominal options appropriate to that category.
- Access state: Requires an established customer identity.
- Failure/recovery: If a category has no available nominals, the form states that plainly and keeps the category switchable.
- Continuation: The customer picks another category or returns later.
FR-3 — Fast order submission (explicit — speed of transaction is the core value)
As a customer, I should be able to submit a top-up order in a short, focused flow, so that the transaction is done quickly rather than through a long form.
- Trigger/input: The customer chooses a category, enters the destination, and picks a nominal.
- Observable result: The order is created and the customer immediately sees its order ID and a "PROSES" status stamp.
- Access state: Requires an established customer identity.
- Failure/recovery: A missing or malformed destination, or a failed write, produces an inline message and preserves every entered value so nothing must be retyped.
- Continuation: The customer can submit another order or leave the form.
FR-4 — Order review and processing by the operator (explicit — the operator processes orders)
As a Shop Owner / Counter Operator, I should be able to review submitted top-up orders and mark each one SELESAI or BATAL, so that every order reaches a definite outcome.
- Trigger/input: The operator opens the Orders workspace and acts on a row.
- Observable result: The row's status stamp changes to SELESAI (red) or BATAL (muted) and the change persists.
- Access state: Requires an established operator identity.
- Failure/recovery: If the status change fails to persist, the row reverts to its previous stamp and an inline message explains the failure.
- Continuation: The operator continues down the queue.
FR-5 — Stock tracking and updating (explicit — the operator tracks stock)
As a Shop Owner / Counter Operator, I should be able to see and update the stock count for each top-up product, so that stock levels stay accurate while I work the counter.
- Trigger/input: The operator edits a stock count in the Stock workspace.
- Observable result: The new count and its last-updated timestamp are shown and persisted.
- Access state: Requires an established operator identity.
- Failure/recovery: If the update fails to persist, the row reverts to its previous count and an inline message explains the failure.
- Continuation: The operator continues updating other rows.
FR-6 — Self-service enrollment (required_inference)
As a person who has no account, I should be able to create my own account and choose whether I am a customer or a counter operator, so that I can begin using the application without an invitation or a provisioning step.
- Trigger/input: The person opens Sign Up and submits name, identifier, password, and role.
- Observable result: The account is created and the person continues into the application as the chosen role.
- Access state: Anonymous — Sign Up is reachable without an identity.
- Failure/recovery: A duplicate identifier or a missing required field produces an inline message naming the field, and everything already typed is retained.
- Continuation: The person corrects the field and resubmits, or switches to Login if the account already exists.
FR-7 — Returning verification (required_inference)
As a returning customer or operator, I should be able to verify my identity and be returned to the page I was trying to reach, so that my orders and the operator workspaces stay bound to the correct person.
- Trigger/input: The person opens Login and submits their identifier and password.
- Observable result: Identity is verified and the person lands on the destination they came for — the Order Form for a customer, Orders for an operator.
- Access state: Anonymous — Login is reachable without an identity.
- Failure/recovery: Wrong credentials produce an inline message; the entered identifier is retained so only the password needs correcting.
- Continuation: The person retries, or switches to Sign Up.
FR-8 — Role-aware access to order and stock work (required_inference)
As the system, I should distinguish customer order access from counter-operator order processing and stock control, so that a customer's own order work and the operator's queue and stock work do not collide.
- Trigger/input: A signed-in person navigates to the Order Form, Orders, or Stock.
- Observable result: A customer reaches the Order Form and their own submitted orders; an operator reaches the Orders and Stock workspaces.
- Access state: All three destinations require an established identity; the Landing, Login, and Sign Up pages do not.
- Failure/recovery: A person who reaches a destination their role does not cover is returned to the page their role does cover, with a plain explanation.
- Continuation: The person continues in the workspace their role owns.
FR-9 — Public explanation of the counter (required_inference)
As an anonymous visitor, I should be able to read what the counter sells and how to start, so that I can decide to order or to sign in.
- Trigger/input: The visitor opens the Landing page.
- Observable result: The visitor sees the counter's identity, the four service lines, and the "ORDER SEKARANG" call to action.
- Access state: Anonymous — no identity required.
- Failure/recovery: If the session check that routes "ORDER SEKARANG" fails, the button routes to Login and the page stays fully readable.
- Continuation: The visitor goes to the Order Form (if signed in as a customer), Login, or Sign Up.
FR-10 — Customer's own order history (required_inference)
As a customer, I should be able to see the orders I have submitted and their current status, so that I know whether my top-up is still being processed or is done.
- Trigger/input: The customer opens their order list after submitting an order.
- Observable result: The customer sees each of their orders with its category, destination, nominal, and current status stamp.
- Access state: Requires an established customer identity; a customer sees only their own orders.
- Failure/recovery: If the list fails to load, the page states that plainly and offers a retry.
- Continuation: The customer submits another order or leaves.
Page 8 of 19
4. User Personas
Page 9 of 19
Shop Owner / Counter Operator
Product context. This person runs the konter. The counter is a street-level micro-retail business whose entire identity is speed: a walk-in customer wants a top-up done in under a minute, and the operator is the one who makes that happen. The operator is at the counter all day, so the application is a working tool they return to constantly, not a place they visit once.
Primary goal. Handle incoming top-up orders fast and keep stock levels accurate, so that no customer waits and no sale is promised against stock that is not there.
Distinct accepted responsibilities. The operator owns the order queue: reviewing submitted orders and driving each one to a definite outcome by marking it SELESAI or BATAL. The operator also owns stock: seeing and updating the stock count for each top-up product. These two responsibilities are the operator's alone — a customer never processes an order or edits stock.
Relevant inputs and decisions. The operator reads order ID, service category, destination, nominal, customer, and created time, and decides whether an order is completed or cancelled. The operator reads product name, category, nominal, and current stock count, and decides what the new count should be.
Interactions with other accepted participants. The operator's work is downstream of the customer's: every order the operator processes was submitted by a customer through the Order Form. The operator does not create orders on the customer's behalf in the accepted scope; the operator's side of the counter begins once an order exists.
Observable success. Orders move out of PROSES into SELESAI or BATAL and stay that way; stock counts match what is actually on the shelf and carry a fresh timestamp.
Page 10 of 19
Customer
Product context. This person walks up to the counter — or reaches the counter's app — wanting one thing: a digital top-up. They are not interested in the counter's internal workings. Their whole relationship with the product is a short, focused transaction.
Primary goal. Place a top-up order for pulsa, kuota, token PLN, or game credits and have it completed without friction.
Distinct accepted responsibilities. The customer owns order submission: choosing a service category, entering the destination (phone number, PLN meter/customer ID, or game account ID), choosing a nominal, and submitting. The customer also owns the ability to look back at their own submitted orders and see whether each is still being processed or is done. The customer never processes an order and never edits stock.
Relevant inputs and decisions. The customer decides which of the four service lines they need, supplies the destination for that line, and picks a nominal. They decide whether to submit another order after the first.
Interactions with other accepted participants. The customer's submitted order is what the Shop Owner / Counter Operator later reviews and marks SELESAI or BATAL. The customer's observable outcome — the status stamp on their own order — is produced by the operator's action, so the two roles meet at the order's status.
Observable success. The order is submitted quickly, the customer receives an order ID and a PROSES stamp immediately, and the order later reads SELESAI.
5. Core User Flows
Page 11 of 19
Flow A — A customer places a top-up order
- Starting context. The customer is on the public Landing page, not signed in. They see the "KONTER DEPRIYAN CELL" masthead, the scrolling service marquee (PULSA • KUOTA • TOKEN PLN • TOP-UP GAME), and the four colour-coded service panels.
- The customer presses "ORDER SEKARANG" — the yellow sticker button pinned to the bottom-left of the hero. Because no identity is established, the button routes them to Login.
- On Login, the customer either verifies an existing identity or follows the link to Sign Up. On Sign Up they enter name, identifier, password, and choose the customer role, and submit. The account is created and they continue into the application as a customer. (If they already had an account, they verify on Login and are returned to the Order Form.)
- The customer lands on the Order Form. They select a service category from the four full-bleed colour bands — pulsa (red), kuota (yellow), token PLN (teal), or top-up game (off-white on red).
- The form shows the destination field for that category and the available nominals. The customer enters the destination (phone number, PLN meter/customer ID, or game account ID) and picks a nominal.
- The customer submits. Observable result: the order is created and the customer immediately sees its order ID and a "PROSES" status stamp in yellow, snapped in at 120ms.
- Failure/recovery. If the destination is missing or malformed, or the write fails, an inline message appears and every entered value is preserved — the customer corrects the field and resubmits without retyping. If the chosen category has no available nominals, the form says so plainly and the customer switches category.
- Continuation. The customer can submit another order, or open their own order list to see the order they just placed.
Flow B — A customer checks their own order status
- Starting context. The customer is signed in and has at least one submitted order.
- The customer opens their own order list. Observable result: each of their orders is shown with its category, destination, nominal, and current status stamp — PROSES, SELESAI, or BATAL.
- Failure/recovery. If the list fails to load, the page states that plainly and offers a retry.
- Continuation. The customer sees that an order has moved to SELESAI and leaves, or submits another order.
Flow C — A counter operator processes the order queue
- Starting context. The operator is signed in with the counter-operator role and opens the Orders workspace. The queue is rendered as a strict ruled tabular grid: order ID, category with its colour code as a row accent, destination, nominal, customer, created time, and status.
- The operator filters the queue by status or by service category using the four-colour filter tabs, and sorts by created time to work oldest-first.
- The operator opens an order and reads its details. Decision: mark it SELESAI (completed) or BATAL (cancelled).
- The operator acts. Observable result: the row's status stamp changes — SELESAI in red, BATAL in muted — snapping in at 120ms, and the change persists so the customer's own order list reflects it.
- Failure/recovery. If the status change fails to persist, the row reverts to its previous stamp and an inline message explains the failure; the operator retries or refreshes the queue.
- Continuation. The operator continues down the queue. If no orders match the current filter, the workspace says so plainly and offers to clear the filter.
Page 12 of 19
Flow D — A counter operator updates stock
- Starting context. The operator is signed in with the counter-operator role and opens the Stock workspace. Products are listed as ruled rows: product name, service category with its colour chip, nominal, current stock count in tabular figures, and last-updated timestamp.
- The operator filters by service category using the four-colour filter tabs, or sorts by name, category, or stock count, to find the product they need.
- The operator edits the stock count inline. Observable result: the new count and a fresh last-updated timestamp are shown and persisted.
- Failure/recovery. If the update fails to persist, the row reverts to its previous count and an inline message explains the failure; the operator retries or refreshes the table.
- Continuation. The operator continues updating other rows. If no products match the current filter, the workspace says so plainly and offers to clear the filter.
Flow E — A returning person verifies identity
- Starting context. A person who already has an account opens Login directly, or is routed there from the Landing page's "ORDER SEKARANG" button.
- The person enters their identifier and password and submits. Observable result: identity is verified and they land on the destination they came for — the Order Form for a customer, Orders for an operator.
- Failure/recovery. Wrong credentials produce an inline message; the entered identifier is retained so only the password needs correcting. The person retries, or switches to Sign Up if they have no account.
- Continuation. The person proceeds with their role's work.
Flow F — A new person enrolls
- Starting context. A person with no account opens Sign Up from the Landing page's top bar or from the Login page's link.
- The person enters name, identifier, and password, and selects their role from two full-bleed rectangular category bands — customer or counter operator.
- The person submits. Observable result: the account is created and they continue into the application as the chosen role.
- Failure/recovery. A duplicate identifier or a missing required field produces an inline message naming the field, and everything already typed is retained. The person corrects the field and resubmits, or switches to Login if the account already exists.
- Continuation. A customer proceeds to the Order Form; an operator proceeds to Orders.
Page 13 of 19
6. Visuals, Colors, and Theme
The creative direction is authoritative for this section. The muse is Paula Scher; the headline idea is typography as architecture — words fill the frame, colour blocks collide, energy over polish. The register is a hand-painted shop sign you can read from across the road, not a SaaS dashboard. The generic indigo/blue-on-white template is forbidden for this project.
Mode. Dark mode only.
Colour tokens (exact hex, by role).
| Role | Hex | Use |
|---|
| Background | #0E0E0E | Black poster ground; carries ~70% of every screen |
| Surface | #1A1A1A | Panels and raised blocks on the black ground |
| Text | #F5F1E8 | Off-white type and rules only |
| Primary | #E8342A | Scher red — primary CTAs, the pulsa/kuota category band, active nav |
| Accent | #F2C400 | Poster yellow — token PLN, and the "PROSES" status stamp |
| Category — top-up game | #1E8C7E | Flat teal, reserved for top-up game category chips |
| Muted | #8A857C | Labels and timestamps |
Four-colour category coding as wayfinding. Pulsa = red #E8342A; kuota = yellow #F2C400; token PLN = teal #1E8C7E; top-up game = off-white #F5F1E8 on red. Every chip, table row accent, filter tab, and status stamp reuses this exact code so the four product lines read like transit lines.
No gradients, no tints — flat poster ink only. Only the four flat poster colours plus black and off-white are permitted. Pastel and tinted palettes are excluded.
Typography.
- Headings: Anton. Display scale, uppercase, tracking tightened to
-0.02em, leading 0.86 so stacked lines lock into a solid typographic block. Headlines fill the container edge-to-edge, not a comfortable measure. Anton never appears below 24px — it is a poster face, not a UI face.
- Body: Archivo (400/600/700) carries all body, labels, form fields, and table data at 15–17px with 1.55 leading.
- Numeric data: nominal, stock counts, and order IDs set in Archivo 700 with tabular figures and
0.04em tracking so columns align like a ledger.
- Type scale (1.5 modular poster scale): display
clamp(44px, 10vw, 144px) (44 mobile / 88 tablet / 144 desktop); section heads 32/48/64; card titles 20/24/28; body 15/16/17; labels 11/12/12 uppercase tracked +0.14em.
- Line-height:
0.86 for display, 1.55 for body, 1.2 for data rows.
- Excluded fonts: Inter, Roboto, Arial, Helvetica, Open Sans, Lato, Poppins, and
system-ui for headings or body. Anton and Archivo only.
Shape language. Hard edges everywhere — 0px radius on cards, inputs, buttons, and panels. The only curves in the system are the diagonal colour bands that slice across section transitions at 6–8 degrees. Rules are 2px solid black or off-white, never hairlines. Buttons are solid flat rectangles with a 3px offset hard shadow in the opposite colour (red button, yellow shadow) — a screen-print misregistration, not a soft drop shadow. Category chips are full-bleed rectangular bands, not pills. Rounded corners, pill buttons, soft drop shadows, glassmorphism, and frosted panels are excluded.
Layout. A 12-column desktop grid with a hard 2px rule under the top bar and a full-bleed typographic masthead spanning all 12 columns. Landing sections alternate between full-bleed type compositions (a single word like "PULSA" at 144px bleeding off the right edge) and dense colour-blocked service panels. The operator workspaces (Orders, Stock) use a strict tabular grid — ruled rows, aligned label/value pairs, status stamps in the right-hand column — so the density is Scher's poster grid, not a soft dashboard. On mobile everything collapses to a single column with the display type still filling 100% of the width, wrapping onto 2–3 stacked lines rather than shrinking.
Imagery. Typography is the image. No stock photography, no 3D blobs. Supporting imagery is flat halftone-cutout operator photography (a hand holding a phone, a counter top) in duotone black + red, used as full-bleed bands behind type at 40% opacity, always cropped so readable text sits on the solid black portion. Decorative elements are Scher-style painted-map geometry: hard-edged diagonal bands and dot-grid patches in the three poster colours. Simple flat pictograms for the four service categories — signal bars, data arrows, lightning bolt, gamepad — drawn in 3px stroke, sized like signage. Photography is never the hero subject.
Readable text and controls stay whole. Headlines, wordmarks, labels, numbers, card text, and controls stay entirely inside the viewport and their container at 375px, 768px, and 1280px, wrapping or scaling (for example font-size: clamp(...) with its mobile size) to fit, and no other element covers any part of them. Imagery, decoration, and motion may be cropped, bled off an edge, rotated, overlapped, or cut as the direction asks, as long as they cover no readable text or control. Moving and scrollable content (the service marquee, filter rows) may cross the viewport edge by design and is judged by whether it actually moves and whether every item becomes fully readable as it passes.
Page 14 of 19
7. Signature Design Concept
The public entry is a full-bleed black poster, not a SaaS hero.
The word "KONTER" is set in Anton at clamp(44px, 10vw, 144px), spanning the full viewport width, flush against the left edge, with "DEPRIYAN CELL" stacked beneath it in the same typographic block, both locked to leading 0.86. There is no centred composition, no subtext paragraph, no button in the middle, and no gradient.
Directly under the type block runs a horizontal red band (#E8342A) 96px tall containing the four service names — PULSA / KUOTA / TOKEN PLN / TOP-UP GAME — as a continuously scrolling marquee in off-white Anton 32px.
The primary CTA "ORDER SEKARANG" is a solid yellow (#F2C400) rectangle with black Anton text, pinned to the bottom-left corner of the hero and overlapping the red band by 24px so it reads as a screen-printed sticker.
A single 6-degree diagonal yellow band slices the bottom-right corner.
Below the hero, the four service lines appear as dense colour-blocked panels, each carrying its category colour and its 3px-stroke pictogram, so the poster resolves into the counter's actual offering. The composition recomposes only accepted content — the counter's identity, its four service lines, and the route into ordering — and introduces no new behaviour, page, or destination.
Page 15 of 19
8. Interaction Model & Motion Direction
Interaction Model: Animated
Motion Tempo: expressive
Hero Dimensionality: flat
Landing Hero Motion Brief
- Focal subject. The typographic masthead itself — "KONTER DEPRIYAN CELL" in Anton at display scale, flush left, leading 0.86 — with the red service marquee band running edge-to-edge beneath it.
- Input → transformation → outcome thesis. As the page loads, each stacked headline line snaps in from the left with a 2px colour-block wipe behind it, so the masthead assembles like a poster being pulled off the press; once assembled, the red band beneath it begins its continuous leftward scroll of "PULSA • KUOTA • TOKEN PLN • TOP-UP GAME •", so the counter's four service lines are always in motion and always readable as they pass. The outcome is a first frame that reads as a shop sign already shouting, with the yellow "ORDER SEKARANG" sticker sitting still and legible against the moving band.
- Motion vocabulary. Type marquees scrolling a service ticker across the full viewport width; staggered word reveals where each stacked headline line snaps in from the left with a 2px colour-block wipe behind it; colour-flip hovers where a red panel inverts to yellow on pointer-enter; status changes stamping in with a 120ms scale-from-1.06 snap. No easing theatrics, no bounce, no float — motion is a printing press, not a spring.
- Composed first frame. Black ground
#0E0E0E. "KONTER" filling the viewport width at the top-left, "DEPRIYAN CELL" stacked directly beneath it, both in off-white #F5F1E8 Anton. The 96px red #E8342A band directly under the type block, already carrying the off-white service names. The yellow #F2C400 "ORDER SEKARANG" sticker pinned bottom-left, overlapping the red band by 24px. A 6-degree yellow diagonal slicing the bottom-right corner. No centred element, no paragraph, no gradient.
- Reduced-motion state. With
prefers-reduced-motion, the ticker becomes a static wrapped row of the four service names, and all reveals render in their final state — the masthead, the red band with its wrapped service names, and the yellow sticker are all fully present and readable with no motion at all.
Page 16 of 19
9. Non-Functional Requirements
NFR-1 — Hand-authored client stack (explicit)
The client must be written as plain HTML, CSS, and JavaScript. No framework is required or assumed. Rationale: the project owner explicitly asked for "codingan html css js dan database".
NFR-2 — Durable database persistence (explicit)
Accounts, orders, and stock must be stored in a database so that they survive a page reload and remain bound to the correct person. Rationale: the project owner explicitly asked for a database; orders and stock are durable state by nature.
NFR-3 — Transaction speed (explicit — speed of transaction is the core value)
The order submission flow must be short and focused, and the operator's order and stock tables must render as dense ruled grids that can be scanned quickly. Rationale: the accepted product intent states that speed of transaction is the point of the product.
NFR-4 — Readable text and controls at every viewport (explicit, from the creative direction)
Headlines, wordmarks, labels, numbers, card text, and controls must stay entirely inside the viewport and their container at 375px, 768px, and 1280px, wrapping or scaling to fit, with no other element covering any part of them. Display type wraps onto more stacked lines rather than shrinking. Rationale: the creative direction makes this a hard constraint.
NFR-5 — Reduced-motion support (explicit, from the creative direction)
Under prefers-reduced-motion, the service ticker must become a static wrapped row of service names, all reveals must render in their final state, and every item must be bringable fully into view. Rationale: the creative direction requires a usable static arrangement.
NFR-6 — Flat poster palette discipline (explicit, from the creative direction)
Only the four flat poster colours plus black and off-white are permitted. No gradients, no tints, no pastel palette, no rounded corners, no soft drop shadows, no glassmorphism. Rationale: the creative direction forbids these explicitly.
NFR-7 — Role-aware access boundary (required_inference)
The Order Form, Orders, and Stock pages must require an established identity; the Landing, Login, and Sign Up pages must remain anonymously reachable. Rationale: a protected destination cannot own the interaction that grants access to itself, and durable person-specific state must stay bound to the correct person.
NFR-8 — Graceful failure on write (required_inference)
Any failed write (order submission, status change, stock update) must revert the interface to its previous state and explain the failure inline, preserving the person's input. Rationale: without this, a failed write would silently lose the person's work.
Page 17 of 19
10. Tech Stack
- Client: Hand-authored HTML, CSS, and JavaScript — explicitly requested by the project owner. No client framework is required.
- Server / API: A lightweight backend exposing the account, order, and stock operations the pages need. Python / FastAPI is the default choice for this layer
[Default — not specified by user].
- Database: A relational database storing accounts, orders, and stock, with orders and stock rows carrying their owning account and timestamps. PostgreSQL is the default choice
[Default — not specified by user]; SQLite is an acceptable substitute for a single-counter deployment.
- Containerisation: Docker / docker-compose for running the app and its database together
[Default — not specified by user].
- Kubernetes: Not required. The deployment is a single counter application and does not need orchestration.
Page 18 of 19
11. Assumptions and Constraints
Source-stated constraints (binding).
- C-1 (explicit) The referenced existing app at
https://konter-kilat-topup.base44.app/ could not be opened during planning; its contents are not confirmed. It is used only as domain context for the top-up counter domain and its four service lines. No feature, flow, or behaviour from it is treated as a requirement.
- C-2 (explicit) The audience/participation question — whether the app is primarily for the shop owner to process orders and track stock, or for customers to place top-up orders themselves — was asked but not answered, so the primary user role remains unconfirmed. This document therefore covers both accepted roles as a closed set, with the role boundary described in FR-8, rather than assuming one is primary.
Assumptions (narrow, labeled).
- A-1 The four service lines — pulsa, kuota, token PLN, and top-up game — are the counter's complete offering, taken from the verified domain context of the reference site.
- A-2 A person enrolling chooses their own role (customer or counter operator) at Sign Up, because no invitation or provisioning boundary was established by the source.
- A-3 A customer sees only their own submitted orders; the operator sees the full order queue. This follows from the accepted role-aware boundary over shared product state.
- A-4 Nominals/denominations per service category are data the counter maintains, not values invented by this document.
- A-5 The application is deployed for a single counter, not a multi-branch operation.
Explicit exclusions (binding).
- No payment-gateway integration.
- No third-party top-up operator API integration for delivering the top-up.
- No customer-facing chat.
- No loyalty programme.
- No multi-branch management.
- No reporting or analytics beyond what the accepted order and stock workflows require.
- No future-horizon features were accepted; nothing in this document is deferred.
Page 19 of 19
12. Glossary
- Konter — an Indonesian neighbourhood counter shop selling digital prepaid top-ups.
- Pulsa — mobile phone credit / airtime top-up.
- Kuota — a mobile data package.
- Token PLN — prepaid electricity credit for the Indonesian state electricity utility, PLN.
- Top-up game — in-game credits or currency for an online game.
- Nominal — the denomination or value of a top-up product (for example a specific pulsa amount or data package size).
- Destination — the identifier the top-up is applied to: a phone number for pulsa or kuota, a PLN meter/customer ID for token PLN, or a game account ID for top-up game.
- Order — a customer's submitted request for one top-up, carrying an order ID, category, destination, nominal, status, created timestamp, and owning account.
- Status stamp — the rotated -3deg status marker on an order row: PROSES (yellow, being processed), SELESAI (red, completed), BATAL (muted, cancelled).
- Operator — the Shop Owner / Counter Operator who processes orders and tracks stock.
- Customer — the person who places a top-up order.
- Poster grid — the ruled, tabular layout used in the Orders and Stock workspaces, with 2px rules, tabular-figure numerals, and status stamps in the right-hand column.
No comments yet. Be the first!